1、类加载过程
类加载器主要做了什么事情:
2、垃圾回收算法
JVM支持垃圾自动回收,我们应用程序执行起来的时候,默认就会存在我们的GC线程
查找垃圾
1.引用计数法(无法解决对象相互引用的问题)
2.根可达算法
1、垃圾回收算法
回收垃圾算法
1.复制算法(内存利用率不高)
将现有的内存空间分为两半A和B,所有的新对象的内存都在A中分配,然后当A用完了之后,就开始对象存活判断,将A中还存活的对象复制到B去,然后一次性将A中的内存空间回收掉。
在分代模型中,Eden区要比Survivor区大这么多(默认8:1),要是一次GC之后的存活对象的大小大于Survivor区,发生内存分配担保。
当发生了上面这种情况,新生代需要老年代的内存空间来做担保,把Survivor存放不下的对象直接存进老年代中。
2.标记清除(产生内存碎片)
首先标记出所有需要回收的对象,然后统一对标记的对象进行回收,当一个大对象在申请空间时无法找到一个连续的大内存就会出发GC
3.标记整理
标记-整理其GC的过程与标记-清除是一样的,只不过会让所有的存活对象往同一边移动,这样一来就不会像标记-清除那样留下大量的内存碎片。
2、常见垃圾回收器
常见的垃圾回收器
Serial,Serial Old是最先发布的垃圾回收器单线程运行,垃圾回收在工作的时候会停止所有工作线程,这个时间成为STW(stop the world)。用户体验很差劲。随后推出了ParNew,ParNewOld两个并行执行的垃圾回收器,发布多CPU的优势。但是在工作时依然会存在STW
1、CMS垃圾回收器
CMS是一款并发老年代垃圾收回器(和工作线程可以同时进行)
和工作线程并发执行会面临问题,采用三色标记算法进行垃圾回收
三色标记:
- 黑色:该对象已经被标记过了,且该对象下的属性也全部都被标记过了。(程序所需要的对象)
- 灰色:该对象已经被标记过了,但该对象下的属性没有全被标记完。(GC需要从此对象中去寻找垃圾)
- 白色:该对象没有被标记过。(对象垃圾)
存在问题:
1、浮动垃圾:并发标记的过程中,若一个已经被标记成黑色或者灰色的对象,突然变成了垃圾,此时,此对象不是白色的不会被清除,重新标记也不能从GC Root中去找到,所以成为了浮动垃圾,这种情况对系统的影响不大,留给下一次GC进行处理即可。
2、漏标:一个未被标记的白色对象被一个黑色对象重新引用,该对象最终会被当作垃圾被清除,解决方法(写屏障),当一个白色对象被黑色对象引用,将黑色对象标记为灰色。其中还存在一个致命的问题:一个灰色的对象当一个属性被标记后指向了一个白色的对象,当前对象为灰色,不会在重新查找太已经找过的属性,最终无法标记。解决方法: gc扫描结束后,出发STW再次进行一个GC,应为之前已经找到了引用树,这次遍历会快的多。
总结: CMS依然存在STW只是时间上会短很多,效率高很多
线上参数
按需配置
-server -Xms4g -Xmx4g -Xmn2g
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
-XX:MaxDirectMemorySize=1g
-XX:SurvivorRatio=10
-XX:+UseConcMarkSweepGC
-XX:CMSMaxAbortablePrecleanTime=5000
-XX:+CMSClassUnloadingEnabled
-XX:CMSInitiatingOccupancyFraction=80
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+ExplicitGCInvokesConcurrent
-Dsun.rmi.dgc.server.gcInterval=2592000000
-Dsun.rmi.dgc.client.gcInterval=2592000000
-XX:ParallelGCThreads=4
-Xloggc:/home/admin/logs/gc.log
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/home/admin/logs/java.hprof
-Djava.awt.headless=true
-Dsun.net.client.defaultConnectTimeout=10000
-Dsun.net.client.defaultReadTimeout=30000