[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。html

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

 

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 .
相关文章
相关标签/搜索