1.垃圾回收器1.1.对象可以在被需要时创建,不再使用时由JVM自动回收1.2.GC是查找不再使用的对象,然后回收这些对象相关内存的过程1.2.1.找到不使用的对象、回收其内存、压缩堆内存1.3.优化垃圾回收器比跟踪指针引起的bug要容易得多(且耗时更少)1.4.VM必须定期搜索堆中不使用的对象1.4.1.从GC根(GC root)对象开始搜索,GC根是可以从堆外被访问的对象,主要包括线程栈和系统类1.4.2.当GC算法找到不使用的对象时,JVM会回收这些对象占用的内存,并将这些内存分配给其他对象2.垃圾回收器运行多个线程2.1.一组执行应用程序逻辑,通常被称为mutator线程2.1.1.作为应用程序逻辑的一部分会改变对象2.2.另一组执行GC,当GC线程跟踪对象引用(用于回收对象)或者在内存中移动对象时,它们必须确保应用程序线程不使用这些对象2.3.所有线程都停止运行的停顿被称为STW停顿(stop-the-world pause)2.3.1.尽量减少这些停顿是优化GC的重中之重3.垃圾回收器分代3.1.分代理由3.1.1.大量对象(有时甚至是大多数对象)是临时对象3.1.2.很多对象的使用时间很短3.2.老年代3.2.1.old generation或tenured generation3.2.2.Full GC3.2.2.1.一般会造成应用程序线程较长时间的停顿3.3.新生代3.3.1.young generation3.3.2.只是整个堆的一部分3.3.2.1.对象首先在新生代中分配3.3.2.2.比处理整个堆要快3.3.3.Eden空间3.3.3.1.占据了新生代的绝大多数空间3.3.3.2.最初对象会被分配到Eden空间3.3.3.3.不再使用的对象被丢弃3.3.3.4.仍在使用的对象被移动到一个Survivor空间或者晋升到老年代3.3.4.Survivor空间3.3.4.1.在回收结束时,Eden空间和一个Survivor空间被清空,新生代中剩余的对象都被压缩到另一个Survivor空间中3.3.5.Minor GC3.3.5.1.Young GC3.3.5.2.当新生代被填满时,垃圾回收器会停止所有的应用程序线程,并清空新生代3.3.5.3.不再使用的对象被丢弃3.3.5.4.仍在使用的对象被移到其他地方4.并发回收器4.1.concurrent collector4.2.低停顿(low-pause)回收器4.3.无停顿(pauseless)回收器4.4.查找的代码可以在不停止应用程序线程的情况下运行4.5.代价是应用程序总体上使用更多的CPU时间4.5.1.避免长时间停顿是以消耗额外的CPU周期为代价的4.6.更难优化以达到最佳性能5.选型5.1.单个请求会受停顿时间的影响,尤其是Full GC时较长时间的停顿5.1.1.减少停顿对响应时间的影响,那么并发回收器可能更合适5.2.如果平均响应时间比异常值(例如第90百分位响应时间)更重要5.2.1.并发回收器可能会产生更好的结果6.GC算法6.1.Serial垃圾回收器6.1.1.最简单的回收器6.1.2.在只有一个CPU可用且额外的GC线程会干扰应用程序的情况下使用(而且是默认的)6.1.2.1.只有一个核心(甚至是以两个CPU形式出现的超线程核心)的虚拟机和Docker容器让这个算法又有了使用的意义6.1.3.使用单线程来处理堆6.1.3.1.处理堆时会停止所有的应用程序线程(不管是Minor GC还是Full GC)6.1.3.2.在Full GC期间,它将完全压缩老年代6.1.4.-XX:+UseSerialGC标志可以开启6.1.5.-XX:-UseSerialGC并不会禁用6.1.5.1.禁用需要设定另外一个垃圾回收器6.2.CMS垃圾回收器6.2.1.第一个并发垃圾回收器6.2.1.1.JDK 8中相当流行6.2.1.2.自JDK 11被正式废弃,而且不鼓励在JDK 8中使用6.2.2.会在Minor GC的过程中停止所有的应用程序线程6.2.3.主要缺陷是它不能在后台处理过程中压缩堆6.2.4.-XX:+UseConcMarkSweepGC标志开启6.2.4.1.默认值是false6.3.Throughput垃圾回收器6.3.1.并行回收器(parallel collector)6.3.2.JDK8中任何有两个或者多个CPU的64位机器的默认垃圾回收器6.3.3.-XX:+UseParallelGC标志6.3.4.-XX:+UseParallelOldGC标志6.3.4.1.已经过时了6.3.4.2.可以禁用这个标志,只对新生代进行并行回收6.4.G1 GC6.4.1.垃圾优先垃圾回收器6.4.2.使用并发回收策略来以最小的停顿回收堆6.4.3.JDK 11和之后版本的默认垃圾回收器6.4.4.-XX:+UseG1GC标志开启