垃圾回收机制的所有信息和资料都是来源于oracle公司对外开放的一些文档,这也是大家不管在哪里看到垃圾回收机制都差不多的原因,这些信息属于JVM公开的文档。
自动垃圾收集是查看堆内存,识别正在使用那些对象以及那些对象未被删除以及删除未使用对象的过程。
使用中的对象或引用的对象意味着程序的某些部分仍然维护指向对象的指针。程序的任何部分都不再引用未使用的对象或未引用的对象,因此可以回收未引用对象使用的内存。
像C这样的编程语言中,分配和释放内存是一个手动过程。在java中,接触分配内存的过程由垃圾收集器自动处理。
该过程的第一步称为标记。这是垃圾收集器识别哪些内存正在使用哪些不在使用的地方。
简单来说,将对象及其引用关系看作一个图,选定活动的对象作为GC Root。然后跟踪引用链条,如果一个对象和GC Roots之间不可达,也就是不存在引用,那么即可认为是可回收对象。
如果一个对象没有被引用就认为可以被GC了。
可以作为GC Root的对象,通过GC Root从上到下所有的Object都找到,顺藤摸瓜。
1.标记-清除(Mark-Sweep)
jvm会扫描所有的对象实例,通过根搜索算法,将活跃对象进行标记,jvm再一次扫描所有对象,将未标记的对象进行清除,只有清除动作,不作任何的处理,这样导致的结果会存在很多的内存碎片。
2.复制(copying)算法
jvm扫描所有对象,通过根搜索算法标记被引用的对象,之后会申请新的内存空间,将标记的对象复制到新的内存空间里,存活的对象复制完,会清空原来的内存空间,将新的内存最为jvm的对象存储空间。这样虽然解决了内存内存碎片问题,但是如果对象很多,重新申请新的内存空间会很大,在内存不足的场景下,会对jvm运行造成很大的影响。
3.标记-整理(Mark-compact)
标记整理实际上是在标记清除算法上的优化,执行完标记清除全过程之后,再一次对内存进行整理,将所有存活对象统一向一端移动,这样解决了内存碎片问题。
根据对象的存活周期,将内存划分为几个区域,不同区域采用合适的垃圾收集算法。新对象会分配到Eden,如果超过 -XX:PretenureSizeThreshold:设置大对象直接进入老年代的阈值。
堆大小=新生代+老年代,新生代与老年代的比例为1:2,新生代细分为一块较大的Eden空间和两块较小的Survivor空间,分别被命名为from和to。 老年代:老年代中使用“标记-清除”或者“标记-整理”算法进行垃圾回收,回收次数相对较少,每次回收时间比较长。
1、大对象直接进入老年代
因为新生代是使用的复制算法,所以要尽量减少复制的内存,所以对象内存到一定的值后就会直接进入老年代。
2、新生代对象年龄到一定程度后进入老年代
每个对象会有一个Age的计数器,初始值为0,每经过一次GC并且存活,这个对象的Age就会加1,如果增加到一定程度(默认为15)。那么就会进入老年代中。
3、动态对象年龄判定
如果在新生代存活区中相同年龄所有对象大小的总和大于存活区的一半,年龄大于或等于该年龄的对象就会直接进入老年代。 比如现在存活区有三个对象,Age分别为2、2、3。那么Age为3的这个对象就会进入老年代。
分代这块必须理解,分代的原因,分代之后数据操作GC操作是怎么做。老年代的GC(标记,清除,整理)
每个线程来执行所有垃圾收集工作,适合单处理器机器。
老年代 -Serial Old -XX:+UseSerialGC
可以在老年代使用,它采用标记整理算法,区别于新生代的复制算法。
串行适合物联网的,单核的,如何量大的话,会存在stop-the-world
server 模式JVM的默认GC 选择,整体算法和Serial 比较相似,区别是新生代 和 老年代GC 都是并行进行。可以设置GC时间或吞吐量等值,可以自行进行适应性调整Eden,Survivor大小和MaxTenuringThreshold的值
也称为吞吐量优先的GC:吞吐量 = 用户代码运行时间/(用户代码运行时间 + GC 时间)
CMS是HotSpot在JDK1.5推出的第一款真正意义上的并发(Concurrent)收集器,第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。 专用老年代,基于标记 - 清除 算法,设计目标是尽量减少停顿时间。 采用的标记-清除算法,存在着内存碎片化问题,长时间运行等情况下发生full GC,导致恶劣的停顿。 CMS会占用更多CPU资源,并和用户线程争抢。 减少了停顿时间,这一点对于互联网web等对时间敏感的系统非常重要,一直到今天,仍然有很多系统使用CMSGC
新生代GC 实现,它实际是Serial GC的多线程版本。可以控制线程数量, 参数: -XX:ParallelGCThreads 最常见的应用场景是配合老娘带的CMS GC工作。 参数: -XX:+UseConcMarkSweepGC
G1(Garbage-First)是在JDK 7u4版本之后发布的垃圾收集器,并在jdk9中成为默认垃圾收集器。通过“-XX:+UseG1GC”启动参数即可指定使用G1 GC。从整体来说,G1也是利用多CPU来缩短stop the world时间,并且是高效的并发垃圾收集器。但是G1不再像上文所述的垃圾收集器,需要分代配合不同的垃圾收集器,因为G1中的垃圾收集区域是分区(Region)的。G1的分代收集和以上垃圾收集器不同的就是除了有年轻代的ygc,全堆扫描的fullgc外,还有包含所有年轻代以及部分老年代Region的MixedGC。
介绍了7种垃圾回收器,有作用在新生代,也有作用在老年代的。也有G1两者都可以兼容的,G1已经基本大规模使用了。比如老年代选择CMS 可以选择新生代 Sertial 和 ParNew
PS:不管是调优也好,先是配合对应的新老对应的垃圾收集器,如果有必要才修改垃圾收集器的参数的,垃圾回收器如何标记垃圾,如何进行垃圾收集的,收集器有哪些?它们是如何配合的。