• JVM-垃圾收集器与内存分配策略-20200705


    垃圾收集前的判断

    1:判断对象“死活”

    引用计数算法:定义略,主流的Java虚拟机并没有选用引用计数算法来管理内存,因为此算法很难解决对象之间的相互循环引用的问题

    可达性分析算法:定义略,可作为GC Roots的对象包括:

       1:虚拟机栈(栈帧中的本地变量表)中引用的对象  2: 方法区中静态类属性引用的对象  3:方法区中常量引用的对象  4:本地方法栈中JNI(Native方法)引用的对象

    2:引用的分类:强引用 > 软引用 > 弱引用 > 虚引用

    3:方法区(虚拟机中的永久代)回收:主要包括废弃常量和无用的类;

    垃圾收集算法

    1:标记-清除算法:大致过程如下(自己理解的,望指正)(最基础,以后的算法基于这种思路并改进不足)

     缺点:效率问题:标记和清除的过程效率都不高;   

           空间问题:标记清除后会产生大量不连续的碎片,可能导致分配大对象时无法找到足够的内存而提前出发新的垃圾收集动作。

    2:复制算法:一般新生代采用,Eden : Survivor : survivor = 8 : 1 : 1,(分配担保:暂时放入老年代)

    3:标记-整理算法:一般老年代采用,过程前面同标记-清除算法,第二次标记后让存活的对象向一段移动,然后直接清理掉边界外的内存

    4:分代收集算法:堆内存中新生代采用赋值算法,老年代采用标记-整理或标记-清除算法

    HotSpot 虚拟机中的算法实现

    可达性分析算法:概念---枚举根节点,OopMap,安全点,安全区域

    垃圾收集器

    HotSpot虚拟机包含的所有的垃圾收集器:任意两个之间的连线说明他们可以搭配使用,没有最好的,只有最适合某个场景的

     1:Serial收集器:单线程收集器,

      缺点:进行垃圾回收时,必须暂停其他所有的工作线程,直到收集结束;

      优点:和其他收集器的单线程相比,简单而高效---没有线程交互的开销

      适用于运行在client模式下的虚拟机----新生代

    2:ParNew 收集器:Serial收集器的多线程版本,适用于运行在Server模式下的虚拟机----新生代

    3:Parallel Scavenge收集器:达到一个可控制的吞吐量,自适应调节策略

    4:Serial Old收集器:老年代的Serial的收集器,单线程,使用标记-整理算法

    5:Parallel Old:Parallel Scavenge的老年代版本,多线程,标记-整理算法,主要和Parallel Scavenge搭配,适合于注重吞吐量的场景

    6:CMS 收集器:Concurrent Mark Sweep ,以获取最短回收停顿时间为目标的收集器,适合重视服务器的响应速度的场景,标记-清除算法

     过程:初始标记  ->  并发标记 ->  重新标记  ->  并发清除     耗时长:并发标记 >= 并发清除 > 重新标记 > 初始标记

    初始标记和重新标记都要停顿所有Java线程(stop the world)并发标记和并发清除过程中收集器线程和用户线程同时工作,因此总体上可以说明内存回收过程是与用户线程并发执行的

    缺点:1:对CPU资源非常敏感  

        2:无法处理浮动垃圾----并发清理阶段用户线程运行产生的垃圾

        3:由于使用标记-清除算法,收集结束会产生大量空间碎片

    7:G1收集器---Garbage-First:面向服务端应用的垃圾收集器

    过程: 初始标记 -> 并发标记 -> 最终标记  -> 筛选回收 

    优点:1:并行与并发--充分利用多CPU及多核环境下的硬件优势,,比如步骤二

      2:分代收集  ---  可以独立管理GC堆,能够采用不同的方式处理新创建的对象、已经存活一段时间、熬过多次GC的对象来获得更好的收集效果

      3:空间整合--- 整体看是标记-整理算法,局部间各region是基于复制算法,都不会产生内存空间碎片

      4:可预测的停顿---建立可预测的停顿时间模型,M毫秒的时间片段内,消耗在垃圾收收集的时间不得超过N毫秒

    理解GC日志

    内存分配与回收

    1:对象优先分配在Eden区,当Eden区没有足够的空间进行分配时,虚拟机将发起一次  Minor GC;新生代分为 Eden : from Survivor : to Survivor = 8 : 1 : 1,复制算法

    2:大对象直接进入老年代,目的是避免在Eden区及两个Survivor 发生大量的内存复制,-XX:PretenureSizeThreshold=3145728,大对象的限制大小参数配置

    3:长期存活的对象直接进入老年代:年龄计数器(Age)--Eden区对象经过其次minorGC 后仍存活,且能被survivor区容纳,会被移动到survivor区,

      Age + 1,如此循环,默认15,移动到老年代,参数配置:-XX:MAxTenuriingThreshold=1

    4:动态对象年龄判断:如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间大小的一半,年龄大于等于该年龄的对象可直接进入老年代

    5:空间分配担保:

  • 相关阅读:
    【人生】未来一段时间的规划
    java new一个对象的过程中发生了什么
    Openwrt missing dependencies for the following libraries:nf_nat.ko
    Lua日期转秒 时间函数os.time()和日期函数os.date()的使用
    lua 命令行参数
    Robot Framework自动化测试Telnet简单示例使用
    VirtualBox安装OpenWrt虚拟机
    C语言中负数的补码存储(1000 0000 表示128)
    Robot Framework自动化测试SSHLibrary简单示例使用
    dkjson实现lua空table编码为数组[]
  • 原文地址:https://www.cnblogs.com/xiaoma000deblog/p/13254073.html
Copyright © 2020-2023  润新知