1 / 115

Sun JDK 1.6 GC ( Garbage Collector )

Sun JDK 1.6 GC ( Garbage Collector ) . http://bluedavy.com 2010-05-13 V0.2 2010-05-19 V0.5 2010-06-01 V0.8. ppt 中未特别强调的 JVM 均指 Sun JDK 1.6.0. Java :自动内存管理 为什么还 需要学习 GC ?. OOM? GC 成为支撑更高并发量的瓶颈 ?. only 介绍 使用 通常问题查找 Tuning 实现. GC : Garbage Collector. 不是只负责内存回收. 还决定了内存分配. 使用.

glen
Download Presentation

Sun JDK 1.6 GC ( Garbage Collector )

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Sun JDK 1.6 GC(Garbage Collector) http://bluedavy.com 2010-05-13 V0.2 2010-05-19 V0.5 2010-06-01 V0.8 ppt中未特别强调的JVM均指Sun JDK 1.6.0

  2. Java:自动内存管理 为什么还需要学习GC? OOM? GC成为支撑更高并发量的瓶颈?

  3. only介绍 使用 通常问题查找 Tuning 实现

  4. GC:Garbage Collector 不是只负责内存回收 还决定了内存分配

  5. 使用 Hotspot是如何分配内存的 Hotspot什么时候回收内存

  6. 内存结构 -Xss PC寄存器 本地方法栈 局部变量区 -XX:PermSize –XX:MaxPermSize 操作数栈 JVM方法区 栈帧 JVM堆 JVM方法栈 -Xms -Xmx 备注:在Hotspot中本地方法栈和JVM方法栈是同一个,因此也可用-Xss控制

  7. 内存分配 1、堆上分配 大多数情况在eden上分配,偶尔会直接在old上分配细节取决于GC的实现这里最重要的优化是TLAB 2、栈上分配 原子类型的局部变量或基于EA后标量替换转变为原子类型的局部变量 3、堆外分配 DirectByteBuffer 或直接使用Unsafe.allocateMemory,但不推荐这种方式

  8. 内存回收(Garbage Collection) GC要做的是将那些dead的对象所占用的内存回收掉; 1、Hotspot认为没有引用的对象是dead的 2、Hotspot将引用分为四种 Strong、Soft、Weak、Phantom Strong即默认通过Object o=new Object()这种方式赋值的引用; Soft、Weak、Phantom这三种则都是继承Reference; 在Full GC时会对Reference类型的引用进行特殊处理: Soft:内存不够时一定会被GC、长期不用也会被GC,可通过 -XX:SoftRefLRUPolicyMSPerMB来设置; Weak:一定会被GC,当被mark为dead,会在ReferenceQueue中通知; Phantom:本来就没引用,当从jvm heap中释放,会通知。

  9. 内存回收 经IBM研究,通常运行的程序有98%的对象是临时对象,因此 Sun Hotspot对JVM堆采用了分代的方式来管理,以提升GC的 效率。

  10. JVM堆:分代 -Xmn New Generation Eden S0 S1 Old Generation -XX:SurvivorRatio 备注:通常将对新生代进行的回收称为Minor GC;对旧生代进行的回收称为Major GC,但由于 Major GC除并发GC外均需对整个堆进行扫描和回收,因此又称为Full GC。

  11. 新生代可用GC 串行GC (Serial Copying) 并行GC (ParNew) 并行回收GC (Parallel Scavenge) 我该用哪个呢?

  12. 新生代可用GC—串行 1. client模式下默认GC方式,也可通过-XX:+UseSerialGC来强制指定; 2. eden、s0、s1的大小通过-XX:SurvivorRatio来控制,默认为8,含义 为eden:s0的比例,启动后可通过jmap –heap [pid]查看。

  13. 新生代可用GC—串行 默认情况下,仅在TLAB或eden上分配,只有两种状况会在旧生代分配: 1、需要分配的大小超过eden space大小; 2、在配置了PretenureSizeThreshold的情况下,对象大小大于此值。 public class SerialGCDemo{ public static void main(String[] args) throws Exception{ byte[] bytes=new byte[1024*1024*2]; byte[] bytes2=new byte[1024*1024*2]; byte[] bytes3=new byte[1024*1024*2]; Thread.sleep(3000); byte[] bytes4=new byte[1024*1024*4]; Thread.sleep(3000); } } -Xms20M –Xmx20M –Xmn10M –XX:+UseSerialGC -Xms20M –Xmx20M –Xmn10M -XX:PretenureSizeThreshold=3145728 –XX:+UseSerialGC

  14. 新生代可用GC—串行 当eden space空间不足时触发。 public class SerialGCDemo{ public static void main(String[] args) throws Exception{ byte[] bytes=new byte[1024*1024*2]; byte[] bytes2=new byte[1024*1024*2]; byte[] bytes3=new byte[1024*1024*2]; System.out.println(“step 1"); byte[] bytes4=new byte[1024*1024*2]; Thread.sleep(3000); System.out.println(“step 2"); byte[] bytes5=new byte[1024*1024*2]; byte[] bytes6=new byte[1024*1024*2]; System.out.println(“step 3"); byte[] bytes7=new byte[1024*1024*2]; Thread.sleep(3000); } } -Xms20M –Xmx20M –Xmn10M –XX:+UseSerialGC

  15. 新生代可用GC—串行 上面示例之所以会是触发一次minor和一次full,在于Serial GC的这个规则: 在回收前Serial GC会先检测之前每次Minor GC时晋升到旧生代的平均大小是否大 于旧生代的剩余空间,如大于,则直接触发full,如小于,则取决于 HandlePromotionFailure的设置。

  16. 新生代可用GC—串行 public class SerialGCDemo{ public static void main(String[] args) throws Exception{ byte[] bytes=new byte[1024*1024*2]; byte[] bytes2=new byte[1024*1024*2]; byte[] bytes3=new byte[1024*1024*2]; System.out.println("step 1"); bytes=null; byte[] bytes4=new byte[1024*1024*2]; Thread.sleep(3000); System.out.println("step 2"); byte[] bytes5=new byte[1024*1024*2]; byte[] bytes6=new byte[1024*1024*2]; bytes4=null; bytes5=null; bytes6=null; System.out.println("step 3"); byte[] bytes7=new byte[1024*1024*2]; Thread.sleep(3000); } } -Xms20M –Xmx20M –Xmn10M –XX:+UseSerialGC -Xms20M –Xmx20M –Xmn10M -XX:-HandlePromotionFailure –XX:+UseSerialGC

  17. 新生代可用GC—串行 上面示例在两个参数时执行效果之所以不同,在于Serial GC的这个规则: 触发Minor GC时: 之前Minor GC晋级到old的平均大小 < 旧生代剩余空间 < eden+from使用空间 当HandlePromotionFailure为true,则仅触发minor gc,如为false,则触发full。

  18. 新生代可用GC—串行 新生代对象晋升到旧生代的规则 1、经历多次minor gc仍存活的对象,可通过以下参数来控制: 以MaxTenuringThreshold值为准,默认为15。 2、to space放不下的,直接放入旧生代;

  19. 新生代可用GC—串行 public class SerialGCThreshold{ public static void main(String[] args) throws Exception{ SerialGCMemoryObject object1=new SerialGCMemoryObject(1); SerialGCMemoryObject object2=new SerialGCMemoryObject(8); SerialGCMemoryObject object3=new SerialGCMemoryObject(8); SerialGCMemoryObject object4=new SerialGCMemoryObject(8); object2=null; object3=null; SerialGCMemoryObject object5=new SerialGCMemoryObject(8); Thread.sleep(4000); object2=new SerialGCMemoryObject(8); object3=new SerialGCMemoryObject(8); object2=null; object3=null; object5=null; SerialGCMemoryObject object6=new SerialGCMemoryObject(8); Thread.sleep(5000); } } class SerialGCMemoryObject{ private byte[] bytes=null; public SerialGCMemoryObject(int multi){ bytes=new byte[1024*256*multi]; } } -Xms20M –Xmx20M –Xmn10M –XX:+UseSerialGC -Xms20M –Xmx20M –Xmn10M –XX:+UseSerialGC -XX:MaxTenuringThreshold=1

  20. 新生代可用GC—串行 把上面代码中的object1修改为如下: SerialGCMemoryObject object1=new SerialGCMemoryObject(2); -Xms20M –Xmx20M –Xmn10M –XX:+UseSerialGC

  21. 新生代可用GC—串行 上面示例中object1在第二次minor gc时直接转入了old,在于Serial GC的 这个规则: 每次Minor GC后会重新计算TenuringThreshold (第一次以MaxTenuringThreshold为准) 计算的规则为: 累积每个age中的字节,当这个累计值 > To Space的一半时,对比此时的age和 MaxTenuringThreshold,取其中更小的值。 可通过PrintTenuringDistribution来查看下次minor gc时的TenuringThreshold 值:Desired survivor size 524288 bytes, new threshold 1 (max 15),其中 的new threshold 1即为新的TenuringThreshold的值。 例如在上面的例子中: 当第一次Minor GC结束时,遍历age table,当累积age 1的字节后,发现此时所 占用的字节数 > To Space的一半,因此将TenuringThreshold赋值为1,下次 Minor GC时即把age超过1的对象全部转入old。

  22. JVM新生代可用GC—串行 [GC [DefNew: 11509K->1138K(14336K), 0.0110060 secs] 11509K->1138K(38912K), 0.0112610 secs] [Times: user=0.00 sys=0.01, real=0.01 secs]

  23. 新生代可用GC—ParNew CMS GC时默认采用,也可采用-XX:+UseParNewGC强制指定; eden、s0、s1的大小通过-XX:SurvivorRatio来控制,默认为8,含义 为eden:s0的比例。 默认情况下其内存分配和回收和Serial完全相同,只是回收的时候为多线程 而已,但一旦开启-XX:+UseAdaptiveSizePolicy则有些不同。

  24. 新生代可用GC—ParNew [GC [ParNew: 11509K->1152K(14336K), 0.0129150 secs] 11509K->1152K(38912K), 0.0131890 secs] [Times: user=0.05 sys=0.02, real=0.02 secs] 如启动参数上设置了-XX:+UseAdaptiveSizePolicy,则会输出 [GC [ASParNew: 7495K->120K(9216K), 0.0403410 secs] 7495K->7294K(19456K), 0.0406480 secs] [Times: user=0.06 sys=0.15, real=0.04 secs]

  25. 新生代可用GC—PS server模式时默认的GC方式,也可采用-XX:+UseParallelGC强制指定; eden、s0、s1的大小可通过-XX:SurvivorRatio来控制,但默认情况下以-XX:InitialSurivivorRatio为准,此值默认为8,代表的为新生代大小 : s0,这点要特别注意。

  26. 新生代可用GC—PS 大多数情况下,会在TLAB或eden上分配。 如下一段代码: public class PSGCDemo{ public static void main(String[] args) throws Exception{ byte[] bytes=new byte[1024*1024*2]; byte[] bytes2=new byte[1024*1024*2]; byte[] bytes3=new byte[1024*1024*2]; Thread.sleep(3000); byte[] bytes4=new byte[1024*1024*4]; Thread.sleep(3000); } } -Xms20M –Xmx20M –Xmn10M –XX:SurvivorRatio=8 –XX:+UseParallelGC

  27. 新生代可用GC—PS 上面示例中的bytes4之所以会直接在旧生代分配,在于PS GC的这个规则: 当TLAB、eden上分配都失败时,判断需要分配的内存大小是否 >= eden space的一半大小,如是就直接在旧生代分配。

  28. 新生代可用GC—PS eden space分配不下,且需要分配的对象大小未超过eden space的一半或old区分配失败, 触发回收; public class PSGCDemo{ public static void main(String[] args) throws Exception{ byte[] bytes=new byte[1024*1024*2]; byte[] bytes2=new byte[1024*1024*2]; byte[] bytes3=new byte[1024*1024*2]; System.out.println(“step 1"); byte[] bytes4=new byte[1024*1024*2]; Thread.sleep(3000); System.out.println(“step 2"); byte[] bytes5=new byte[1024*1024*2]; byte[] bytes6=new byte[1024*1024*2]; System.out.println(“step 3"); byte[] bytes7=new byte[1024*1024*2]; Thread.sleep(3000); } } -Xms20M –Xmx20M –Xmn10M –XX:SurvivorRatio=8 –XX:+UseParallelGC -XX:+PrintGCDetails –XX:verbose:gc

  29. 新生代可用GC—PS 上面示例之所以会是触发一次minor和两次full,在于PS GC的这个规则: 1、在回收前PS GC会先检测之前每次PS GC时晋升到旧生代的平均大小是否大于 旧生代的剩余空间,如大于,则直接触发full; 2、在回收后,也会按上面规则进行检测。

  30. 新生代可用GC—PS 新生代对象晋升到旧生代的规则 1、经历多次minor gc仍存活的对象,可通过以下参数来控制: AlwaysTenure,默认false,表示只要minor GC时存活,就晋升到旧生代; NeverTenure,默认false,表示永不晋升到旧生代; 上面两个都没设置的情况下,如UseAdaptiveSizePolicy,启动时以 InitialTenuringThreshold值作为存活次数的阈值,在每次psgc后会动态调整如不使用UseAdaptiveSizePolicy,则以MaxTenuringThreshold为准。 2、to space放不下的,直接放入旧生代;

  31. 新生代可用GC—PS 在回收后,如UseAdaptiveSizePolicy,PS GC会根据运行状况动态调整eden、to 以及TenuringThreshold的大小。 不希望动态调整可设置-XX:-UseAdaptiveSizePolicy。 如希望跟踪每次的变化情况,可在启动参数上增加:PrintAdaptiveSizePolicy

  32. 新生代可用GC—PS • [GC [PSYoungGen: 11509K->1184K(14336K)] 11509K->1184K(38912K), 0.0113360 secs] • [Times: user=0.03 sys=0.01, real=0.01 secs]

  33. 旧生代可用的GC 串行GC (Serial MSC) 并行 MS GC (Parallel MSC) 并行 Compacting GC (Parallel Compacting) 并发GC (CMS) 我该用哪个呢?

  34. 旧生代可用GC—串行 client方式下默认GC方式,可通过-XX:+UseSerialGC强制指定。

  35. 旧生代可用GC—串行 触发机制 1、old gen空间不足; 2、perm gen空间不足; 3、minor gc时的悲观策略; 4、minor GC后在eden上分配内存仍然失败; 5、执行heap dump时; 6、外部调用System.gc,可通过-XX:+DisableExplicitGC来禁止。 ps: 如CollectGen0First为true(默认为false),则先执行minor GC;

  36. 旧生代可用GC—串行 • [Full GC [Tenured: 9216K->4210K(10240K), 0.0066570 secs] 16584K->4210K(19456K), [Perm : 1692K->1692K(16384K)], 0.0067070 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]

  37. 旧生代可用GC—并行MSC server模式下默认GC方式,可通过-XX:+UseParallelGC强制指定; 并行的线程数 cpu core<=8 ? cpu core : 3+(cpu core*5)/8 或通过-XX:ParallelGCThreads=x来强制指定。

  38. 旧生代可用GC—并行MSC 触发机制和串行完全相同 ps: 如ScavengeBeforeFullGC为true(默认值),则先执行minor GC;

  39. 旧生代可用GC—并行MSC • [Full GC [PSYoungGen: 1208K->0K(8960K)] [PSOldGen: 6144K->7282K(10240K)] 7352K->7282K(19200K) [PSPermGen: 1686K->1686K(16384K)], 0.0165880 secs] [Times: user=0.01 sys=0.01, real=0.02 secs]

  40. 旧生代可用GC—并行Compacting 可通过-XX:+UseParallelOldGC强制指定; 并行的线程数 cpu core<=8 ? cpu core : 3+(cpu core*5)/8 或通过-XX:ParallelGCThreads=x来强制指定。

  41. 旧生代可用GC—并行Compacting 触发机制和并行MSC完全相同

  42. 旧生代可用GC—并行Compacting • [Full GC [PSYoungGen: 1224K->0K(8960K)] [ParOldGen: 6144K->7282K(10240K)] 7368K->7282K(19200K) [PSPermGen: 1686K->1685K(16384K)], 0.0223510 secs] [Times: user=0.02 sys=0.06, real=0.03 secs]

  43. 旧生代可用GC—并发 可通过-XX:+UseConcMarkSweepGC来强制指定,并发的线程数 默认为:( 并行GC线程数+3)/4,也可通过ParallelCMSThreads指定;

  44. 旧生代可用GC—并发 • 触发机制 • 1、当旧生代空间使用到一定比率时触发; • JDK V 1.6中默认为92%,可通过PrintCMSInitiationStatistics(此参数在V 1.5中不能用)来查看这个值到底是多少; • 可通过CMSInitiatingOccupancyFraction来强制指定,默认值并不是赋值在了这个值上,是根据如下公式计算出来的: • ((100 - MinHeapFreeRatio) +(double)(CMSTriggerRatio * MinHeapFreeRatio) / 100.0)/ 100.0; • MinHeapFreeRatio默认值: 40 CMSTriggerRatio默认值: 80 • 2、当perm gen采用CMS收集且空间使用到一定比率时触发; • perm gen采用CMS收集需设置:-XX:+CMSClassUnloadingEnabled • JDKV 1.6中默认为92%; • 可通过CMSInitiatingPermOccupancyFraction来强制指定,同样,它是根据如下公式计算出来的: • ((100 - MinHeapFreeRatio) +(double)(CMSTriggerPermRatio* MinHeapFreeRatio) / 100.0)/ 100.0; • MinHeapFreeRatio默认值: 40 CMSTriggerPermRatio默认值: 80

  45. 旧生代可用GC—并发 触发机制 3、Hotspot根据成本计算决定是否需要执行CMS GC; 可通过-XX:+UseCMSInitiatingOccupancyOnly来去掉这个动态执行的策略。 4、外部调用了System.gc,且设置了ExplicitGCInvokesConcurrent; 需要注意,在JDK 6中,在这种情况下如应用同时使用了NIO,可能会出现bug。

  46. 旧生代可用GC—并发 public class CMSGCOccur{ public static void main(String[] args) throws Exception{ byte[] bytes=new byte[1024*1024*2]; byte[] bytes1=new byte[1024*1024*2]; byte[] bytes2=new byte[1024*1024*2]; byte[] bytes3=new byte[1024*1024*1]; byte[] bytes4=new byte[1024*1024*2]; Thread.sleep(5000); } } -Xms20M –Xmx20M –Xmn10M -XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly -XX:+PrintGCDetails -Xms20M –Xmx20M –Xmn10M -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails

  47. 旧生代可用GC—并发 Promotion Failed minor GC了,to space空间不够,往old跑,old也满了,so..解决方法:增大to space,增大old,或降低cmsgc触发时机 Concurrent mode failure old要分配内存了,但old空间不够,此时cmsgc正在进行,so..解决方法:增大old,降低cmsgc触发的old所占比率。 在这两种情况下,为了安全,JVM转为触发Full GC。

  48. 旧生代可用GC—并发 [GC [1 CMS-initial-mark: 13433K(20480K)] 14465K(29696K), 0.0001830 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [CMS-concurrent-mark: 0.004/0.004 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] [CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] CMS: abort preclean due to time [CMS-concurrent-abortable-preclean: 0.007/5.042 secs] [Times: user=0.00 sys=0.00, real=5.04 secs] [GC[YG occupancy: 3300 K (9216 K)][Rescan (parallel) , 0.0002740 secs] [weak refs processing, 0.0000090 secs] [1 CMS-remark: 13433K(20480K)] 16734K(29696K), 0.0003710 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [CMS-concurrent-sweep: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 当在启动参数上设置了-XX:+UseAdaptiveSizePolicy后,上面的日志中的CMS会变为ASCMS CMS GC Log解读

  49. GC—默认组合

More Related