1.1 总的来说,java虚拟机的内存是由运行时数据区,执行引擎,本地接口库(native)以及本地方法库构成。
1.2 运行时数据区具体又包括:方法区,虚拟机栈,本地方法栈,堆,以及程序计数器。
1.3 运行时数据区中的 方法区 与 堆 是所有线程共享的数据区,虚拟机栈,本地方法栈,以及程序计数器是线程隔离的数据区(线程独享)。
java虚拟机内存组成1.2.1 程序计数器(program counter register) 线程私有
程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的 行号指示器。
字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等功能都需要依赖这个计数器来完成。
java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的。在任何一个确定的时刻,一个处理器都只会执行一条线程中的指令。因此为了确保线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,称之为 线程私有内存。
如果线程执行的是一个java方法,计数器记录的是正在执行的虚拟机字节码指令的地址,如果正在执行的是native方法,则计数器的值为空(undefined)。
此内存区域是jvm中唯一 一个没有规定OutOfMemoryError 的区域。
1.2.2 java虚拟机栈(java Virtual Mechine Stacks) 线程私有
1)虚拟机栈是描述 java 方法执行的内存模型,每一个方法执行时都会创建一个栈帧,用来存储局部变量,操作数栈,动态链接,方法出口等。每一个方法的调用到执行完成的过程,都对应着一个栈帧在虚拟机栈中的入栈到出栈的过程。
2)虚拟机栈的生命周期与线程的生命周期一致。
3)该部分内存为线程私有
4)java虚拟机中的内存称之为堆内存与栈内存,其中的栈内存指的就是 虚拟机栈,或者是虚拟机栈中局部变量表部分
5)局部变量表所需要的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,方法运行期间不会改变局部变量表的大小。
6)异常处理:jvm中规定,如果线程请求的栈深度大于虚拟机所允许的深度 会抛出StackOverflowError
具体的虚拟机栈帧结构会在后续的章节中进行分析
1.2.3本地方法栈(Native Method Stack) 线程私有
本地方法栈的功能与虚拟机栈基本相同,不同的是虚拟机栈执行的是Java方法,本地方法栈执行的native方法
1.2.4 java堆(java heap) 所有线程共享
1)一般来说,java堆是虚拟机所管理的最大的一块内存区域。
2)java堆是所有线程共享的内存区域,在虚拟机启动的时候创建。
3)创建该内存区域的唯一目的就是用来存放创建的对象实例,几乎所有的对象实例都是在这里分配内存(并不那么绝对)
4)这个区域是垃圾收集器管理的主要区域,也称为GC堆。
5)线程共享的java堆中可能划分出多个线程私有的分配缓存区(Thread Local Allcation Buffer TLAB),其目的是为了更快的进行内存分配。
6)无论怎么划分,划分的目的只是为了更好的回收内存,或者更快的分配内存,不会改变存放的内容,java堆存放的依旧是对象实例
1.2.5 方法区(Method Area) 线程共享区域
1)方法区用来存储已经被 虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据
2)在hotspot虚拟机上,很多人将方法区称之为 永久代
3)在jdk 1.7 中 hotspot已经把原本放在永久代的 字符串常量池 移除
4)这个区域的垃圾收集主要是针对 常量池的回收 以及 类型的卸载
1.2.6运行时常量池(Runtime Constant Pool)
1)运行时常量池是属于方法区的一部分
2)用于存放编译期生成的各种字面量跟符号引用(在类加载完成后进入)
3)常量不一定要在编译时才能产生,运行时也能将新的变量放入池中,利用这种特新最多的是 String 的 intern()方法。
网友评论