[讨论] jvm垃圾回收线程个数和次数
546144153
2012-08-02
问几个问题,先表示一下感谢。不知道大家相关问题都去哪里看文档?现在总是觉得查不到靠谱的文档,或者文档不够解惑。
1:如果jvm已经在垃圾回收的过程中,这时分配大量内存,没有OOM,会不会触发另外一次垃圾回收,这次垃圾回收是不是立即执行?假设使用的是CMS收集器。 2:大量的concurrent mode failure主要是什么原因引起的?如何避免。 3:垃圾回收有没有频率限制? |
|
RednaxelaFX
2012-08-05
1、要先说明几个术语。首先是mutator与collector。
以Java为上下文,简单来说GC自身是collector,非GC的部分(例如说应用自身的代码)是mutator。最简单的情况是mutator与collector不能同时运行——mutator运行的时候collector不能动,collector运行的时候mutator不能动。这样的GC通常背称为stop-the-world的GC。 如果mutator与collector可以一起动,这样的collector就是concurrent collector。 在HotSpot VM中,只有CMS与G1是带有concurrent阶段的;在concurrent阶段应用的代码可以跟GC的代码同时执行。也就是说,在这些concurrent阶段中,才有可能发生“JVM正在做垃圾收集,而应用代码同时尝试分配内存“的情况。 如果不是在concurrent阶段,或者collector自身就不是concurrent的,那mutator申请内存跟collector回收垃圾一定不会同时发生。 HotSpot VM主要从eden为新生Java对象分配内存。如果eden满了就会触发minor GC。与CMS搭配使用的young gen collector通常是ParNew。ParNew可以在CMS的concurrent阶段中执行而不会冲突。 2、concurrent mode failure发生在当CMS已经在工作并处于concurrent阶段中,而Java堆的内存不够用需要做major GC(full GC)的时候。换句话说,old gen内存的消耗速度比CMS的收集速度要高,CMS收集器跟不上分配速度的时候会发生concurrent mode failure。要从理论上彻底避免这种情况就必须改变GC的实现方式,这里不讨论这种“理论情况”。现实中要减少或者说延迟concurrent mode failure的发生,最根本的方式就是应用自己降低产生垃圾的速度——别乱创建新垃圾对象。其它治标的办法有例如说加大old gen,或者减少对象从young gen晋升到old gen的数量之类的(通过调整survivor space大小、TargetSurvivorRatio、tenuring threshold之类的)。 3、GC自身没有特定的频率限制。只是看应用能承受到什么程度而已。HotSpot VM有GCOverheadLimit参数可以让GC占用的时间超过一定比例的时候通过抛OOM来通知应用,除此之外没有啥限制。 |
|
546144153
2012-08-09
谢谢撒加。那这样说,两个垃圾回收线程是可能同时运行的了?再问下,你们平时都去哪里看资料呢~?
|
|
RednaxelaFX
2012-08-12
先从官网上有的资料开始吧,例如http://www.oracle.com/technetwork/java/javase/tech/index-jsp-136373.html
然后这篇必读:http://www.oracle.com/technetwork/java/javase/tech/memorymanagement-whitepaper-1-150020.pdf (虽然有点老但基本概念还是没差的) 我自己的话因为直接参与JVM的研发所以我会经常直接从代码里找答案⋯ |
|
winit
2013-12-29
hi,撒加,根据你的解释,我的理解是如果old区足够,理论不会发生concurrent mode failure(除去jdk1.5 CMSMaxAbortablePrecleanTime的bug):
“concurrent mode failure发生在当CMS已经在工作并处于concurrent阶段中,而Java堆的内存不够用需要做major GC(full GC)的时候.” 但是最近我们做loading测试发现gc log,每隔30次minor gc就有一次concurrent mode failure. 环境以及相关设置是: linux 服务器 jdk1.5.0_08 -server -XX:MaxPermSize=256M -Xmn400m -Xmx1536m -Xms1536m -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=5 -XX:+UseParNewGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+PrintHeapAtGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:-OmitStackTraceInFastThrow -XX:+PrintTenuringDistribution new区400m,old区域有1G。 每次concurrent mode failure都是old区域450M左右,那也还将近有600多m,肯定够放哦,为什么这个时候会出现呢?我理解也不应该是内存碎片引起的吧 995.316: [GC {Heap before gc invocations=375: par new generation total 368640K, used 361274K [0x812d0000, 0x9a2d0000, 0x9a2d0000) eden space 327680K, 98% used [0x812d0000, 0x94f2abb8, 0x952d0000) from space 40960K, 91% used [0x97ad0000, 0x99f43d40, 0x9a2d0000) to space 40960K, 0% used [0x952d0000, 0x952d0000, 0x97ad0000) concurrent mark-sweep generation total 1163264K, used 441890K [0x9a2d0000, 0xe12d0000, 0xe12d0000) concurrent-mark-sweep perm gen total 175272K, used 111507K [0xe12d0000, 0xebdfa000, 0xf12d0000) 995.316: [ParNew: 361274K->361274K(368640K), 0.0000190 secs]995.316: [CMS (concurrent mode failure): 441890K->184481K(1163264K), 0.8789610 secs] 803164K->184481K(1531904K)Heap after gc invocations=376: par new generation total 368640K, used 0K [0x812d0000, 0x9a2d0000, 0x9a2d0000) eden space 327680K, 0% used [0x812d0000, 0x812d0000, 0x952d0000) from space 40960K, 0% used [0x97ad0000, 0x97ad0000, 0x9a2d0000) to space 40960K, 0% used [0x952d0000, 0x952d0000, 0x97ad0000) concurrent mark-sweep generation total 1163264K, used 184481K [0x9a2d0000, 0xe12d0000, 0xe12d0000) concurrent-mark-sweep perm gen total 175272K, used 111430K [0xe12d0000, 0xebdfa000, 0xf12d0000) } , 0.8793040 secs] |