Jvm gc小议

JVM GC小议

JVM体系结构概况

其中GC主要作用于方法区和堆。

其中:

  • 堆区 储存的全是对象,被所有线程共享,没有基本类型和对象的引用,只有对象本身。
  • 栈区 每个线程有一个栈区,保存基础类型的对象和自定义对象的引用,其中的内容是私有的,其他线程不能访问。
  • 方法区 又称为静态区,同样被共享,包含所有class和static变量。

GC 算法

引用计数法

最简单的gc算法,原理是每个对象里保存该对象被引用的次数,每当发生引用增减时自我更新,当计数变成0的时候表示不再被引用,则可释放相应内存空间。优点是容易实现,预测准确。缺点是对象维护一个引用计数器本身也需要一定量的开销,容易产生线程不同步现象,另外无法判别循环引用的情况出现。

标记清除/标记压缩算法

首先从根开始将可能被引用的对象用递归的方式进行标记,然后将没有标记到的对象作为垃圾进行回收。如果是压缩的话就是对所有标记到的对象往一端滑动放到一起,将没标记的视为垃圾回收。

复制收集算法

将从根开始被引用的对象复制到另外的空间中,然后,再将复制的对象所能够引用的对象用递归的方式不断复制下去。


Sun Hotspot内存管理

采用分代管理的办法

由于不同对象生命周期不同,所用gc算法效率也不同,因此Permanent主要负责以方法区为主的非堆内存,堆内存分为年起代和年老代两种,其中年轻代又由一个Eden区和两个大小对等的Survivor区组成。

GC类型:

  • Minor GC 针对年轻代GC,年轻代中对象周期短、数量大、GC频率高,采用复制算法
  • Major GC 针对老年代GC,GC频率相对较低,采用标记-权利-压缩结合优化的算法
  • Full GC 针对永久代、年轻代和老年代的GC

新生代可用GC

Serial copy、Parallel Scavenge(多线程垃圾回收)、 ParNew,均使用复制算法。

新对象的内存分配都是现在Eden中进行,当Eden空间不够了会触发年轻代上的GC(在Eden和Survivor上),称之为Minor GC。每个对象都有一个“年龄”,即经历minor GC的次数,当“年龄”足够大的时候,会从Survivor中升级到年老代中。

年老代可用GC

Serial MSC、Parallel Compacting、CMS(Concurrent Mark Sweep)

当有对象从Survivor升级到Tenured区域但是无新空间给对象时,会触发年老代上的GC,称为Major GC。

Serial Copy

串行执行,对经历多次Minor GC仍存活的对象或者大小超过eden space或Survivor剩余size的对象可晋升为年老对象。

Parallel Scavenge

并行执行标记清除和标记压缩,消除清除产生的磁盘碎片

Concurrent Mark Sweep

CMS相对于Parallel Scavenge而言,减少了暂停应用程序的时间,基本上沿用了标记清除算法,略有不同,分为四个阶段:

  • Initial Mark 其实是Stop-The-World的过程,暂停应用程序的运行,但是不会标记Tenured区域中所有对象,只会从根节点开始,标记到其一层子节点,随后立即恢复程序运行,将暂停影响控制到最低。
  • Concurrent Mark 以IM阶段标记的节点为根节点,重新标记可到达的对象,这步骤不需要暂停应用。
  • Remark 由于Concurrent Mark阶段是跟程序同时运行的,所以无法保证所有对象都被标记了,所以再次暂停程序确保所有对象被标记。
  • Concurrent Sweep 恢复程序执行,执行Sweep。

调优和监控

  • 堆大小调优:一般来说堆越大越好,但受硬件系统限制,设置参数-Xms堆最小值-Xmx堆最大值
  • 年轻代大小:增大Eden大小会降低Minor GC频率,设置参数-Xmn年轻代大小,调整晋升策略,让对象尽可能留在Survivor中

JVM参数

  • -XX:+PrintGC 输出GC简要信息
  • -XX:+PrintGCDetails 输出GC详细信息
  • -XX:+PrintGCTimeStamps 输出GC时间戳
  • -XX:+PrintGCApplicationStoppedTime 输出GC暂停时间
  • -Xlogg 输出日志信息到文件

命令行工具

  • 查看内存使用情况、heap dump:jmap+jhat
  • 查看GC情况:jstat
Kaka Chen /
Published under (CC) BY-NC-SA in categories Java  tagged with Java  JVM