JVM内存结构(二)

  • 运行时数据区(规范规定)

JVM内存结构(二)_第1张图片

程序计数器 :Java支持多线程同时执行,每个线程都有自己的PC Register,线程正在执行的方法叫做当前方法,如果是java代码,PC Register里面存放的就是当前正在执行的指令地址,如果是C代码,则为空。

虚拟机栈JVM Stacks:线程私有的,它的生命周期与线程相同。虚拟机栈是描述的Java方法执行的内存模型:每个方法在执行的同时会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出入口等信息。每一个方法从调用到执行完成的过程,就对应一个栈帧在虚拟机栈从入栈到出栈的过程。

Java堆:Java虚拟机所管理的内存中最大的一块。堆是所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。Java堆可以处于物理上不连续的内存空间,只要逻辑上是连续即可。

方法区:各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

常量池(Run-Time Constant Pool):运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息常量池,用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

本地方法栈Native Method Stacks:与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。

Java内存结构模型

JVM内存结构(二)_第2张图片 

Metaspace包含Class Package Method Field 字节码 常量池 符号引用 等等

CCS:32位指针的Class   -XX:+UseCompressedClassPointers

CodeCache: JIT编译后的本地代码 JNI使用的代码

垃圾回收算法

判断一个对象是否是垃圾,需要进行回收。

引用计数法:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,但无法解决对象相互循环引用的问题。Java未采用。

枚举根节点,可达性分析法。根节点:类加载器、Thread、虚拟机栈的本地变量表、Static成员、常量引用、本地方法栈的变量

标记清除法:首先标记出所有的需要回收的对象,在标记完成以后统一回收所有被标记的对象。适合在老年代进行垃圾回收,比如CMS收集器就是采用该算法进行回收的

          特点:空间的问题,标记清除以后会产生大量不连续的空间碎片,空间碎片太多可能会导致程序运行过程需要分配较大的对象时候,无法找到足够连续内存而不得不提前触发一次垃圾收集。

标记整理法:首先标记出所有需要回收的对象,让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。适合老年代进行垃圾收集,parallel Old(针对parallel scanvange gc的) gc和Serial old收集器就是采用该算法进行回收的。

          特点:不会产生空间碎片,但是整理会花一定的时间。

复制算法:它先将可用的内存按容量划分为大小相同的两块,每次只是用其中的一块。当这块内存用完了,就将还存活着的对象复制到另一块上面,然后把已经使用过的内存空间一次清理掉。适合新生代区进行垃圾回收。serial new,parallel new和parallel scanvage

         特点:没有内存碎片,只要移动堆顶指针,按顺序分配内存即可。代价是将内存缩小位原来的一半。

         由于新生代都是朝生夕死的,所以不需要1:1划分内存空间,可以将内存划分为一块较大的Eden和两块较小的Suvivor空间。每次使用Eden和其中一块Survivor。当回收的时候,将Eden和Survivor中还活着的对象一次性地复制到另一块Survivor空间上,最后清理掉Eden和刚才使用过的Suevivor空间。其中Eden和Suevivor的大小比例是8:1。缺点是需要老年代进行分配担保,如果第二块的Survovor空间不够的时候,需要对老年代进行垃圾回收,然后存储新生代的对象,这些新生代当然会直接进入来老年代。
         一般是把java堆分成新生代和老年代,这样就可以根据各个年待的特点采用最适合的收集算法。在新生代中,每次垃圾收集都会有大量的对象死去,只有少量存活,所以选用复制算法。老年代因为对象存活率高,没有额外空间对他进行分配担保,所以一般采用标记整理或者标记清除算法进行回收。

你可能感兴趣的:(jvm)