• JVM系列-分代收集垃圾回收


    Java自动垃圾回收(Automatic Garbage Collection)是自动回收上不再使用的内存,new的对象在程序中没有引用指向它,就会被回收。回收的实现很多,有Reference Counting Collector/Tracing Collector/Compacting Collector/Coping Collector/Generational Collector/Adaptive Collector。本文记录的是HotSpot Java VM采用的Generational Collector(分代收集器)

    为什么分代?

    下图是随着时间的推移,经历垃圾回收后存活下的数据大小情况。可以看出大部分对象存活期很短,随着时间的推移越来越少的对象存活下来。因此,可以针对不同的堆内存采取不同的回收频率和方法,以提高JVM性能。


    堆内存分代概念

    下图是Generation GC对内存结构的划分:


    Eden:用于new对象时分配的内存空间,大部分初始new的对象位于该空间

    Survivor Space:在eden中经历垃圾回收后,存活下来的对象被存储在该空间

    tenured Space:在survivor space中存在了一段时间的对象会被挪到该空间

    Permanent Space:JVM使用的元数据,如classloader加载的class/method定义(反射后的数据)。

    Code Cache:用于编译和存储原代码

    其中Permanent Space和Code Cache不属于generation collector回收范围。但是当Permanent Space已用完,且需要加载新class时,会触发Full GC对Permanent进行回收,卸载(清除)那些不再被需要的class。

    如何分代收集

    new对象会最初分配在eden中,当eden满时触发minor garbage collection。

    Minor GC(又称作Young GC)针对young generation:

    • eden/S0中存活的对象被复制到S1中,eden/S0被清空
    • 每次minor gc,存活对象的age会加1,当age超过阈值后,对象被存到old generation中。
    • S0和S1是相对的,第一次Minor GC时S0/S1都是空的,从eden往S0复制,第二次minor gc就是从eden/S0往S1复制,下一次是eden/S1到S0,以后依次类推。

    Minor GC采用的是复制收集,young generation中的对象大部分是不再使用,所以复制存活下来的对象到新空间,旧空间整体回收,这样的一个过程会更快。

    随着Minor GC的发生,被promoted到old generation的对象越来越多,当old generation满时就触发了major garbage collection。Major GC(又称作Old GC)针对old generation,采取marking-deletion-compact(标记-清除-压缩内存)的方法。(补:压缩内存,就是把活着的对象放在一块,省出连续的空闲内存,便于分配)

    通常Major GC又被认为是Full GC,因为Major GC发生时会伴随着Minor GC:一次Minor GC将存活对象放到old generation时导致old generation满了,从而导致Major GC。这一段时间整个堆内存表现出的现象是都进行了garbage collection。

    建议

    Minor/Major GC都是Stop the World事件,应用程序会停止执行,直到GC完成。Major GC发生时,整个堆内存都受到了影响,持续时间长。

    所以应该尽量避免或减少Major GC(减少被放到old generation的对象);尽量最大化堆内存。

    实际使用

    启动java程序时通过设置相关命令参数调节垃圾回收的方法、阈值或频率来优化GC对程序的影响,常用命令如下:

    Switch Description
    -Xms Sets the initial heap size for when the JVM starts.
    -Xmx Sets the maximum heap size.
    -Xmn Sets the size of the Young Generation.
    -XX:PermSize Sets the starting size of the Permanent Generation.
    -XX:MaxPermSize Sets the maximum size of the Permanent Generation

    GC的串并行

    串行GC在JavaSE 5/6上是默认方式,常用于对暂停时间要求不高、客户端类型的应用程序上,也适用于应用程序的数目比CPU多的情况,这样GC时JVM之间的影响小。MB级别的堆内存进行Full GC时只需要几秒。设置的命令是-XX:+UseSerialGC。

    并行GC使用多线程进行Minor GC,线程数默认与CPU数相等。设置的相关命令是-XX:+UseParallelGC和-XX:ParallelGCThreads=<desired number>(指定线程数)。-XX:+UseParallelOldGC会设置Minor GC和Major GC都采用多线程。

    CMS

    并发标记清除收集器(Concurrent Mark Sweep)用于old generation的垃圾回收,它尽力减少程序的暂停时间,GC工作和应用程序的线程并发执行。它不做compact(压缩)堆内存,省去了内存的拷贝和移动。当内存碎片过多无法满足分配时,就直接重新分配一块更大的堆内存。CMS适用于webserver或者查询类的应用

    相关命令:-XX:+UseConcMarkSweepGC和-XX:ParallelCMSThreads=<n>(设置并行线程数)

    G1 Garbage Collector

    G1回收器在Java7中被引进,希望能取代CMS,它主要是并发、增量式的compact内存,以取得低暂停。相关命令:-XX:+UseG1GC

    一个实例

    java -Xmx12m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseParallelOldGC -jar Java2demo.jar

    参考:http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

  • 相关阅读:
    《C++ Primer》学习笔记第2章 变量和基本类型
    Java学习笔记类的继承与多态特性
    Java的冒泡排序问题
    新起点,分享,进步
    MVC2中Area的路由注册实现
    了解一下new关键字实现阻断继承的原理
    利用Bing API开发的搜索工具(MVC+WCF)
    ASP.NET MVC中错误处理方式
    const和readonly内部区别
    WCF中校验参数的实现方式(一)
  • 原文地址:https://www.cnblogs.com/whuqin/p/4981963.html
Copyright © 2020-2023  润新知