Java 内存模型 - 内存区域划分
1、运行时数据区域
Java 虚拟机在执行Java程序时会把所管理的内存划分成多不同的数据区域分别有:方法区、堆、虚拟机栈、本地方法栈、程序计数器;各个分区分别有各自用途。
1.1 程序计数器
程序计数器是一快较小的内存空间;它可以看作是当前线程所执行字节码的行号指示器。虚拟机的概念模型中,字节码解释器工作时就是通过改变程序计数器的值来选择下一个需要执行的字节码指令,分支、循环、跳转等基础功能。都需要依赖计数器来完成。有人说Java中没有指针的概念,其实我倒是认为计数器也就类似一个被指向的指针。
由于Java虚拟机中的多线程是通过轮流切换并分配处理器执行时间来实现的,在任何一个确定的时间片内,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都有一个独立的程序计数器,各个线程中的程序计数器互补影响,独立存储。这类内存区域被称为 ” 线程私有 “ 内存。
如果当前线程正在执行一个 Java 方法,程序计数器则记录的是当前整在执行的虚拟机字节码指令的地址。
1.2 Java 虚拟机栈
Java 虚拟机栈与程序计数器一样也是 线程私有,它的声明周期与线程相同。虚拟机栈描述的是 Java 方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链表、方法出口等信息。每个方法从调用到执行完成的过程,就对应一个栈帧在虚拟机中入栈到出栈的过程。
局部变量表存放了编译期可知的各种基本数据类型、对象引用类型;存储的是变量或对象引用的起始地址。
此区域规定了两种异常情况:如果当前线程请求的栈深度大于虚拟机所允许的深度,将抛出 StackOverflowError 异常;如果当前虚拟机栈可以动态扩展,如果扩展时无法申请到足够内存,就会抛出 OutOfMemoryError 异常。
1.3 本地方法栈
本地方法栈与虚拟机栈所发挥的做用非常相似,它们之间的区别是虚拟机栈执行的是 Java (字节码) 服务,本地方法栈执行的是 虚拟机使用到的本地 Native 方法。
此区域会抛出两个异常:StackOverflowError 异常、OutOfMemoryError 异常。
1.4 Java 堆
对于大多数程序而言,Java 堆内存是 虚拟机所管理的内存中最大的一块。Java 堆是被所有线程所共享的一块内存地址。在虚拟机启动时创建。此区域唯一的目的就是存放对象实例。这块区域也是垃圾回收主要回收的区域;有时也会被称之为” GC 堆 “。
如果在堆内存中没有内存完成实例分配,并且堆也无法扩展时将抛出OutOfMemoryError 异常。
1.5 方法区
方法区与Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。虽然Java 虚拟机规范把方法区描述为一个堆的一个逻辑部分;但是他却有一个别名 :Non - Heap(非堆) ,目的应该是与Java 堆分开。
当方法区无法满足内存分配需求时将抛出 OutOfMemoryError 异常。
1.6 运行时常量池
运行时常量是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法的运行时常量池中存放。
运行时常量池有一个特性是具备动态性,Java 语言并不要求常量一定是编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量。运行期间也可以将新的常量放入常量池。此特性用的较多的是 String 类的 Intern() 方法。
当常量池无法在申请到内存时将会抛出 OutOfMemoryError 异常。
1.7直接内存 。
2.1 对象创建....
2.2对象在内存中的布局....
2.3对象的访问定位....
未完待续!