• JVM 垃圾回收


    1. 如何判断垃圾可以回收

    (1)引用计数算法:引用时,计数+1,引用失效,计数-1,零时回收;缺点是遇到互相引用导致都不为零

    (2)可达性分析算法(Java用):扫描堆中的对象,沿着GC Root对象为起点的引用链看能否找到该对象,如果能则其仍然存活,不能则判定为可回收的对象。

    可作为GC Root的对象:栈帧中的局部变量,参数,临时变量;静态变量;常量;同步锁持有对象;Class对象

    2. 五种引用(由强至弱)

    • 强引用:传统的正常引用,只要引用关系还在,就不会被回收
    • 软引用:在系统将要内存溢出前,会把这些对象进行二次回收,如果回收后还是没有足够内存,才会抛出内存溢出异常(java.lang.ref.SoftReference)
    • 弱引用:当垃圾回收器开始工作时,就会回收弱引用关联的对象
    • 虚引用:为一个对象设置虚引用,在该对象被回收是会收到一个系统通知,是否有虚引用不会对其生存时间有影响。虚引用Cleaner,在ByteBuffer对象被回收后,其占用的直接内存地址还在,此时把虚引用Cleaner放到引用队列,执行Unsafe.freeMemory来释放直接内存。
    • 终结器引用(补):当对象被垃圾回收时,把对象加入引用队列(入队等待),之后通过终结器引用找到待回收的对象,调用对象的finalize()方法。注:由于处理引用队列线程优先级很低,所以不推荐用finalize()会回收对象。

    3. 垃圾回收算法

    (1)标记清除:先标记,然后清除,清除时就是把对象的起终地址记入空闲地址队列

    优点:速度快  缺点:产生内存碎片

    (2)标记整理:先标记,再把剩余的对象紧凑到一起

    优点:解决了外部碎片  缺点:速度较慢

    (3)标记复制:将内存划分出大小相等的两块,其中一块为原始,一块空白,把存活的对象复制到空白区(移动堆指针,按序分配无碎片)

    优点:无内存碎片,高效  缺点:占用太多空间

    4. 分代回收

    (1)对象首先分配在Eden区

    (2)新生代空间不足时,会触发minor gc,Eden和From中存活的对象被复制到To中,这些对象年龄+1,然后From和To指针交换

    (3)Minor gc会阻塞其他用户进程stop the world(因为对象地址在发生改变,不停止其他进程会错误),等垃圾回收结束再恢复运行

    (4)当对象寿命超过阈值时,它会晋升到老年代,最大寿命是15

    (5)当老年代空间也不足时,会先尝试Minor gc,若空间仍不足,会触发Full gc(标记+整理,较慢),若还不足,会触发out of Memory

    5. 几种垃圾回收器

    (1)串行垃圾回收器:Serial(复制算法)+SerialOld(标记整理算法)

    发生垃圾回收时,先让所有线程在一个安全点停止,等待垃圾回收结束以后其他线程继续工作

    (2)吞吐量优先回收器(垃圾回收时间占总运行时间比例最小,并行):Parallel+ParallelOld

    MaxGCPauseMillis:设置回收花费总时间尽量不超过该设定值

    GCTimeRatio:垃圾收集时间占总时间的比率

    (3)响应时间优先垃圾回收器(单次垃圾回收时间最短,并发):

    ParNew+CMS(标记清除)  垃圾回收和用户进程可以同时进行

    (4)G1垃圾回收器(在延迟可控的情况下获得尽可能高的吞吐量)

    1)G1把堆内存分成若干大小相同的Region,每个Region都可以是Eden,Survivor或Old,通过G1HeapRegionSize可以设置每个Region大小(弱化分代概念,引入分区思想)

    2)工作过程(三个流程循环进行):

    a. 新生代回收:和其他垃圾收集器新生代回收一样,Eden->Survivor->Old

    b. 新生代回收+并发标记(老年代占用到整堆45%时会开始)

    • 初始标记:仅标记GC Root能关联到的对象,有STW但很短
    • 并发标记:可以和用户进程并发,扫描整个堆的对象图,耗时长

    c. 混合回收(会对E,S,O全面回收)

    • 最终标记:短暂STW,标记并发阶段又产生变动的对象
    • 筛选回收:暂停用户线程,多线程并行,把存活的Region复制到空的Region,然后把旧的Region清理

    3)G1和CMS的新生代回收与Serial和Parallel一样,在老年代收集时,先会触发并发标记到筛选回收的过程,如果并发处理速度小于垃圾生成速度,才会Full gc(STW时间更长)

    4)优化:JDK 8u20版本里,所有新分配的字符串放入一个队列,在新生代收集时判断是否有相同字符串,如果有,让他们引用同一个对象

    8u40版本中,经过并发标记,如果发现一个类加载器的所有类都不再使用,则卸载所有它加载的类

    8u60版本中,如果一个对象大小超过Region一半,则称为巨型对象,G1不会对巨型对象拷贝,且会优先回收巨型对象

    6. GC调优

    (1)由于 Full GC 的成本远高于 Minor GC,因此尽可能将对象分配在新生代,适当通过“-Xmn”命令调节新生代大小,最大限度降低新对象直接进入老年代的情况

    (2)新生代空间Xmn不能太大或太小,建议25%-50%

    如果小了,新生代会发生频繁的Minor gc,有STW;如果大了,老年代空间会小,发生Full gc概率更大,而且空间大了回收时间会较长

    (3)大对象可以考虑放入老年代,否则占用新生代空间,-XX:PretenureSizeThreshold可以设置直接进入老年代的对象大小

    (4)-XX:MaxTenuringThreshold 设置对象进入老年代的年龄大小,减少老年代的内存占用,降低Full gc 发生的频率

    (5)设置稳定的堆大小,堆大小设置有两个参数:-Xms 初始化堆大小,-Xmx 最大堆大小。

    (6)如果满足下面的指标,则一般不需要进行 GC 优化:

    • Minor GC 执行时间不到50ms;
    • Minor GC 执行不频繁,约10秒一次;
    • Full GC 执行时间不到1s;
    • Full GC 执行频率不算频繁,不低于10分钟1次。
  • 相关阅读:
    [Swift]LeetCode773. 滑动谜题 | Sliding Puzzle
    [Swift]LeetCode771. 宝石与石头 | Jewels and Stones
    [Swift]LeetCode770. 基本计算器 IV | Basic Calculator IV
    [Swift]LeetCode769. 最多能完成排序的块 | Max Chunks To Make Sorted
    [Swift]LeetCode768. 最多能完成排序的块 II | Max Chunks To Make Sorted II
    转 玩转Bash变量
    转 shell脚本学习指南
    转: 两个 Shell 网站: explainshell 和 shellcheck
    转 BAT CMD 批处理文件脚本总结(中文)
    转 windows 下 Oracle 导出表结构
  • 原文地址:https://www.cnblogs.com/Kinghao0319/p/14460136.html
Copyright © 2020-2023  润新知