java深度-----GC
垃圾收集的实现:1。引用计数:一个A对象,如果有程序使用了这个引用对象,那么引用计数加1,当一个对象使用完毕之后引用计数减1,那么引用计数为0的时候,则可以回收他不能识别循环引用2。跟踪收集如果A对象引用了B对象,那么虚拟机会记住这个引用路径,同时B对象引用了C对象,那么也会记录这个路径如果一个对象没有在路径图中,那么可以收集缺点:需要维护一张引用的全景图,增加了内存开销,和图的遍历开销3.基于对象跟踪的分代增量收集基于对象跟踪---说明是由跟踪收集发展而来的,分代是指对堆进行了合理的划分增量收集:不是每一次全部收集,而是累积的增量收集Sun的JVM将整个堆分为三代:YoungGen,OldGen和PermGen(持久区),对YoungGen GC是相对高效和快速的,YoungGen中,经历了若干次的 GC依然存活的对象(说明这些对象使用频率高,不应该马上回收,所以让他们养老而不是直接干掉),"晋升"到OldGen.内存占用较大的对象,则直接分配到OldGen(因为这种中型对象肯定不会被马上回收,会占用一定得生存时间,比如一个数据库连接,我们需要对他进行缓存,需要反复利用,不会马上回收,所以重型对象放到老年区可以使得他回收更慢),而PermGen 中用于存放长时间存活的对象,如 Class对象基础数据信息,以及全局应用配置信息Eden survivor spaces virtual -------------Young-----------------最开始一个对象会放到Young中的Eden,经过一定的时间会被复制到survivor spaces ,有些可能被复制到年老区,被赋值剩余后的对象会被回收。细致分析:年轻区被进一步分为一个Eden区和两个Survior Space,而两个Suriveor Space在同一时刻,总有一个是空的,这个空的Survivor Space被称为To Space,另外一个则被称为From Space,在年轻区进行GC时,Eden中存活的对象会被copy到To Space中(大对象直接被拷贝到OldGen),From Space 中尚不够Old资格的对象也被copy到To Space中,而剩余的则"晋升"到OldGen中。当To Space不足时,那么本该被拷贝到To Space中的对象则被Tenured(拷贝到了年老对象当中)。。。。这里会带来性能问题哈--因为年老对象会被认为是不应该轻易回收的,所以考量他回收的条件相对复杂得多,所以对年老对象的回收比对年轻对象的回收耗资源得多,他甚至会挂起你的应用来收集资源,超卡。。。。。SUN JVM提供了调节Surivor Space大小的参数,当GCLog中出现Tenured字样时,就可能是Surivor Space不够大造成的。当年老区没有足够的空间,无法接纳由年轻晋升来的对象,那么YoungGen Collection Algorithm(年轻区算法)将会停止,整个GC将会进行年老区域算法(因为JVM会认为,年轻区中这时也存在年老对象,当然需要使用年老算法啦)--术语:叫做"全收集",对于OldGen不能只看其人有空闲就认为其大小已经足够,因为很可能一次年轻区的拷贝就可能触发全收集小收集:当分配器不能满足分配请求时,先触发一个小收集,他只收集年轻区,因为年轻区的许多对象已经死亡,复制收集器完全不用分析死亡原因,所以小收集快,高效下面是阿里的邮件:Dear all: 最近在测试环境经常出现应用的jboss进程在运行了一段时间后crash的情况,在应用的jboss日志中出现以下出错信息:# JRE version: 6.0_18-b07# Java VM: Java HotSpot(TM) 64-Bit Server VM (16.0-b13 mixed mode linux-amd64 )# Problematic frame:# V [libjvm.so+0x6227df]## An error report file with more information is saved as:# /home/6080/work/intl-myaliexpress/deploy/hs_err_pid29858.log## If you would like to submit a bug report, please visit:# http://java.sun.com/webapps/bugreport/crash.jsp到底是什么原因导致以上情况的发生呢?那我们就需要查看具体的hs_err_pid29858.log日志文件来找答案了。? 在该文件的第17行有以下信息:Current thread (0x00000000542e5800): GCTaskThread [stack: 0x00000000415a1000,0x00000000416a2000] [id=29861]说明jvm在crash时,执行的是线程是GCTaskThread。? 我们再来看具体出了什么问题,在文件的第251——261行有以下内容:=>0x00000000542e5800 (exited) GCTaskThread [stack: 0x00000000415a1000,0x00000000416a2000] [id=29861]VM state:at safepoint (normal execution)VM Mutex/Monitor currently owned by a thread: ([mutex/lock_event])[0x00000000542cddf0] Threads_lock - owner thread: 0x0000000054334800[0x00000000542ce2f0] Heap_lock - owner thread: 0x00002aab00003000HeapPSYoungGen total 349120K, used 348912K [0x00002aaae46d0000, 0x00002aaaf9c20000, 0x00002aaaf9c20000)eden space 348672K, 100% used [0x00002aaae46d0000,0x00002aaaf9b50000,0x00002aaaf9b50000)从上面的日志可以肯定是Young GC的时候发生了异常,导致JVM crash。在询问了老董和伯虎后,发现这个是JDK1.6.0_18的已知bug,bug report地址:http://bugs.sun.com/view_bug.do?bug_id=6896647其主要原因是card-marking performance optimization算法在实现的时候有瑕疵,在某些情况下会引起heap corruption。这个情况主要发生在新创建的大对象和Eden space大小差不多,然后jvm做young GC的时候。 解决方案:在启动参数中增加-XX:-ReduceInitialCardMarks将性能优化策略关闭。