转载:JVM GC机制

转载于:http://blog.csdn.net/taijianyu/article/details/6554213

Java性能剖析]Sun JVM 内存管理和垃圾回收

       内存管理和垃圾回收是JVM 非常关键的点,对Java性能的剖析而言,了解内存管理和垃圾回收的基本策略非常重要。本篇对Sun JVM 6.0的内存管理和垃圾回收做大概的描述。

      1.内存管理 
      在程序运行过程当中,会创建大量的对象,这些对象,大部分是短周期的对象,小部分是长周期的对象,对于短周期的对象,需要频繁地进行垃圾回收以保证无用对 象尽早被释放掉,对于长周期对象,则不需要频率垃圾回收以确保无谓地垃圾扫描检测。为解决这种矛盾,Sun JVM 的内存管理采用分代的策略。 
      1)年轻代(Young Gen):年轻代主要存放新创建的对象,内存大小相对会比较小,垃圾回收会比较频繁。年轻代分成1个Eden Space和2个Suvivor Space(命名为A和B) 
当对象在堆创建时,将进入年轻代的Eden Space。 
垃圾回收器进行垃圾回收时,扫描Eden Space和A Suvivor Space,如果对象仍然存活,则复制到B Suvivor Space,如果B Suvivor Space已经满,则复制 Old Gen 
扫描A Suvivor Space时,如果对象已经经过了几次的扫描仍然存活,JVM 认为其为一个Old对象,则将其移到Old Gen。 
扫描完毕后,JVM 将Eden Space和A Suvivor Space清空,然后交换A和B的角色(即下次垃圾回收时会扫描Eden Space和BSuvivor Space。

      我们可以看到:Young Gen垃圾回收时,采用将存活对象复制到到空的Suvivor Space的方式来确保不存在内存碎片,采用空间换时间的方式来加速内存垃圾回收。 
      2)年老代(Tenured Gen):年老代主要存放JVM 认 为比较old的对象(经过几次的Young Gen的垃圾回收后仍然存在),内存大小相对会比较大,垃圾回收也相对没有那么频繁(譬如可能几个小时一次)。年老代主要采用压缩的方式来避免内存碎片 (将存活对象移动到内存片的一边),当然,有些垃圾回收器(譬如CMS垃圾回收器)出于效率的原因,可能会不进行压缩。 
      3)持久代(Perm Gen):持久代主要存放类定义、字节码和常量等很少会变更的信息

1. Heap设定与垃圾回收
Java Heap分为3个区,Young,Old和Permanent。Young保存刚实例化的对象。当该区被填满时,GC 会将对象移到Old区。Permanent区则负责保存反射对象,本文不讨论该区。
JVM 的Heap分配可以使用-X参数设定,
-Xms 初始Heap大小
-Xmx java heap最大值
-Xmn young generation的heap大小

 JVM 有2个GC 线程。第一个线程负责回收Heap的Young区。第二个线程在Heap不足时,遍历Heap,将Young 区升级为Older区。Older区的大小等于-Xmx减去-Xmn,不能将-Xms的值设的过大,因为第二个线程被迫运行会降低JVM 的性能。

为什么一些程序频繁发生GC ?有如下原因:
l         程序内调用了System.gc ()或Runtime.gc ()。
l         一些中间件软件调用自己的GC 方法,此时需要设置参数禁止这些GC 。
l         Java的Heap太小,一般默认的Heap值都很小。
l         频繁实例化对象,Release对象。此时尽量保存并重用对象,例如使用StringBuffer()和String()。
如果你发现每次GC 后,Heap的剩余空间会是总空间的50%,这表示你的Heap处于健康状态。许多Server端的Java程序每次GC 后最好能有65%的剩余空间。
经验之谈:
1 . Server 端 JVM 最好将 -Xms 和 -Xmx 设为相同值。为了优化 GC ,最好让 -Xmn 值约等于 -Xmx 的 1/3[2]。
2 .一个 GUI 程序最好是每 10 到 20 秒间运行一次 GC ,每次在半秒之内完成 [2] 。
注意:
1.增加Heap的大小虽然会降低GC 的频率,但也增加了每次GC 的时间。并且GC 运行时,所有的用户线程将暂停,也就是GC 期间,Java应用程序不做任何工作。
2.Heap大小并不决定进程的内存使用量。进程的内存使用量要大于-Xmx定义的值,因为Java为其他任务分配内存,例如每个线程的Stack等。
 
2.Stack的设定
每个线程都有他自己的Stack。 
-Xss 每个线的 Stack 大小

 Stack的大小限制着线程的数量。如果Stack过大就好导致内存溢漏。-Xss参数决定Stack大小,例如-Xss1024K。如果Stack太小,也会导致Stack溢漏。

3.硬件环境
硬件环境也影响GC 的效率,例如机器的种类,内存,swap空间,和CPU的数量。
如果你的程序需要频繁创建很多transient对象,会导致JVM 频繁GC 。这种情况你可以增加机器的内存,来减少Swap空间的使用[2]。
4.4种GC
第一种为单线程GC ,也是默认的GC 。,该GC 适用于单CPU机器。
第二种为Throughput GC ,是多线程的GC ,适用于多CPU,使用大量线程的程序。第二种GC 与第一种GC 相似,不同在于GC 在收集Young区是多线程的,但在Old区和第一种一样,仍然采用单线程。-XX:+UseParallelGC参数启动该GC 。
第三种为Concurrent Low Pause GC ,类似于第一种,适用于多CPU,并要求缩短因GC 造成程序停滞的时间。这种GC 可以在Old区的回收同时,运行应用程序。-XX:+UseConcMarkSweepGC参数启动该GC 。
第四种为Incremental Low Pause GC ,适用于要求缩短因GC 造成程序停滞的时间。这种GC 可以在Young区回收的同时,回收一部分Old区对象。-Xincgc参数启动该GC 。
4种GC 的具体描述参见[3]。
 
参考文章:
2. Performance tuning Java: Tuning steps
3. Tuning Garbage Collection with the 1.4.2 JavaTM Virtual Machine .
posted @ 2015-01-18 20:24  wrencai  阅读(175)  评论(0编辑  收藏  举报