美文网首页我爱编程
JVM垃圾回收策略

JVM垃圾回收策略

作者: suxm | 来源:发表于2018-04-17 11:32 被阅读26次

    java内存区域划分

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来。



    java虚拟机在执行java程序的过程中,会把它管理的内存划分为若干个不同的数据区域,如下图所示
    图片.png
    • 程序计数器

    程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的信号指示器
    每条线程都需要一个独立的程序指示器,是为了程序切换后能恢复到正确的位置。
    此内存区域是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError的区域

    • java虚拟机栈

      Java虚拟机栈是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法执行的同时会创建一个栈帧,栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
      局部变量表存放了编译期间可知的各种基本数据类型,对象引用和returnAddress类型
      局部变量表所需的内存空间在编译期间完成分配,在方法运行期间不会改变局部变量表的大小

    • 本地方法栈
      本地方法栈为虚拟机使用的Nativie方法服务

    • java堆
      java堆是被所有线程共享的内存区域,在虚拟机启动的时候创建,此内存区域的唯一目的就是存放对象的实例
      java堆是垃圾收集器管理的主要区域

    • 方法区
      方法区也是被所有线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
      这区域的内存回收目标主要是针对常量池的回收和类型的卸载,一般而言,这个区域的内存回收比较难以令人满意,尤其是类型的回收,条件相当苛刻,但是这部分区域的内存回收确实是必要的。

    • 运行时常量池
      运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用

    程序计数器、虚拟机栈、本地方法栈3个区域随线程而生、随线程而灭
    栈中的栈帧随着方法的进入和退出而有条不紊地执行着入栈和出栈操作。每一个栈桢中分配多少内存是在类结构已经确定下来就已知的,这几个区域的内存分配和回收多具备确定性,这几个区域不需要过多考虑回收的问题,方法结束或者线程结束时。内存就跟着自动回收了。

    java堆和方法区,只有在程序运行期间才知道会创建哪些对象,内存的分配和回收都是动态的。

    JVM在进行垃圾回收前,需要判断哪些对象是需要回收的

    • 引用计数算法

    给对象添加一个引用计数器,被引用时计数器值+1,引用失效计数器值-1,当计数器值为0时对象不可能再被使用;

    主流Java虚拟机未选用该算法管理内存(未解决对象之间相互循环引用的问题)

    实现简单,判断效率高(应用:FlashPlayer,Python等)

    • 可达性分析算法

    将"GC Roots"对象作为起始节点,向下搜索,搜索走过的路径为引用链;当一个对象到GC Roots没有引用链时,则该对象是不可用的;

    可作为"GC Roots"的对象:

    1.方法区中静态属性引用的对象

    2.方法区中常量引用的对象

    3.虚拟机栈引用的对象 (栈帧中本地变量表)

    4.本地方法栈中JNI引用的对象 (Native方法)

    GC算法

    • 标记 - 清除算法
    <figure> image

    </figure>

    标记-清除算法采用从根集合进行扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未被标记的对象进行直接回收,如上图。

    标记-清除算法不需要进行对象的移动,并且仅对不存活的对象进行处理,在存活的对象比较多的情况下极为高效,但由于标记-清除算法直接回收不存活的对象,并没有对还存活的对象进行整理,因此会导致内存碎片。

    • 复制算法
    image

    复制算法将内存划分为两个区间,使用此算法时,所有动态分配的对象都只能分配在其中一个区间(活动区间),而另外一个区间(空间区间)则是空闲的。

    复制算法采用从根集合扫描,将存活的对象复制到空闲区间,当扫描完毕活动区间后,会的将活动区间一次性全部回收。此时原本的空闲区间变成了活动区间。下次GC时候又会重复刚才的操作,以此循环。

    复制算法在存活对象比较少的时候,极为高效,但是带来的成本是牺牲一半的内存空间用于进行对象的移动。所以复制算法的使用场景,必须是对象的存活率非常低才行,而且最重要的是,我们需要克服50%内存的浪费。

    • 标记 - 整理算法
    image

    标记-整理算法采用 标记-清除 算法一样的方式进行对象的标记、清除,但在回收不存活的对象占用的空间后,会将所有存活的对象往左端空闲空间移动,并更新对应的指针。标记-整理 算法是在标记-清除 算法之上,又进行了对象的移动排序整理,因此成本更高,但却解决了内存碎片的问题。

    JVM为了优化内存的回收,使用了分代回收的方式,对于新生代内存的回收(Minor GC)主要采用复制算法。而对于老年代的回收(Major GC),大多采用标记-整理算法

    相关文章

      网友评论

        本文标题:JVM垃圾回收策略

        本文链接:https://www.haomeiwen.com/subject/ssjukftx.html