HotSpot虚拟机提供了种类繁多的垃圾收集器,选择太多反而令人踌躇难决,若只挑最先进的显然不可能满足全部应用场景,但只用一句“必须因地制宜,按需选用”又未免有敷衍的嫌疑,本节我们就来探讨一下如何选择合适的垃圾收集器。

Epsilon收集器

在G1、Shenandoah或者ZGC这些越来越复杂、越来越先进的垃圾收集器相继出现的同时,也有一 个“反其道而行”的新垃圾收集器出现在JDK 11的特征清单中——Epsilon,这是一款以不能够进行垃圾 收集为“卖点”的垃圾收集器,这种话听起来第一感觉就十分违反逻辑,这种“不干活”的收集器要它何 用?

Epsilon收集器由RedHat公司在JEP 318中提出,在此提案里Epsilon被形容成一个无操作的收集器 (A No-Op Garbage Collector),而事实上只要Java虚拟机能够工作,垃圾收集器便不可能是真正“无操 作”的。原因是“垃圾收集器”这个名字并不能形容它全部的职责,更贴切的名字应该是本书为这一部分 所取的标题——“自动内存管理子系统”。一个垃圾收集器除了垃圾收集这个本职工作之外,它还要负 责堆的管理与布局、对象的分配、与解释器的协作、与编译器的协作、与监控子系统协作等职责,其 中至少堆的管理和对象的分配这部分功能是Java虚拟机能够正常运作的必要支持,是一个最小化功能 的垃圾收集器也必须实现的内容。从JDK 10开始,为了隔离垃圾收集器与Java虚拟机解释、编译、监 控等子系统的关系,RedHat提出了垃圾收集器的统一接口,即JEP 304提案,Epsilon是这个接口的有效 性验证和参考实现,同时也用于需要剥离垃圾收集器影响的性能测试和压力测试。

在实际生产环境中,不能进行垃圾收集的Epsilon也仍有用武之地。很长一段时间以来,Java技术 体系的发展重心都在面向长时间、大规模的企业级应用和服务端应用,尽管也有移动平台(指Java ME而不是Android)和桌面平台的支持,但使用热度上与前者相比要逊色不少。可是近年来大型系统 从传统单体应用向微服务化、无服务化方向发展的趋势已越发明显,Java在这方面比起Golang等后起 之秀来确实有一些先天不足,使用率正渐渐下降。传统Java有着内存占用较大,在容器中启动时间 长,即时编译需要缓慢优化等特点,这对大型应用来说并不是什么太大的问题,但对短时间、小规模 的服务形式就有诸多不适。为了应对新的技术潮流,最近几个版本的JDK逐渐加入了提前编译、面向 应用的类数据共享等支持。Epsilon也是有着类似的目标,如果读者的应用只要运行数分钟甚至数秒, 只要Java虚拟机能正确分配内存,在堆耗尽之前就会退出,那显然运行负载极小、没有任何回收行为 的Epsilon便是很恰当的选择。

收集器的权衡

如果算上Epsilon,本书中已经介绍过十款HotSpot虚拟机的垃圾收集器了,此外还涉及Azul System公司的PGC、C4等收集器,再加上本章中并没有出现,但其实也颇为常用的OpenJ9中的垃圾收 集器,把这些收集器罗列出来就仿佛是一幅琳琅画卷、一部垃圾收集的技术演进史。现在可能有读者 要犯选择困难症了,我们应该如何选择一款适合自己应用的收集器呢?这个问题的答案主要受以下三 个因素影响:

  • 应用程序的主要关注点是什么?如果是数据分析、科学计算类的任务,目标是能尽快算出结果, 那吞吐量就是主要关注点;如果是SLA应用,那停顿时间直接影响服务质量,严重的甚至会导致事务 超时,这样延迟就是主要关注点;而如果是客户端应用或者嵌入式应用,那垃圾收集的内存占用则是 不可忽视的。
  • 运行应用的基础设施如何?譬如硬件规格,要涉及的系统架构是x86-32/64、SPARC还是 ARM/Aarch64;处理器的数量多少,分配内存的大小;选择的操作系统是Linux、Solaris还是Windows 等。
  • 使用JDK的发行商是什么?版本号是多少?是ZingJDK/Zulu、OracleJDK、Open-JDK、OpenJ9抑 或是其他公司的发行版?该JDK对应了《Java虚拟机规范》的哪个版本? 一般来说,收集器的选择就从以上这几点出发来考虑。举个例子,假设某个直接面向用户提供服 务的B/S系统准备选择垃圾收集器,一般来说延迟时间是这类应用的主要关注点,那么:
  • 如果你有充足的预算但没有太多调优经验,那么一套带商业技术支持的专有硬件或者软件解决方 案是不错的选择,Azul公司以前主推的Vega系统和现在主推的Zing VM是这方面的代表,这样你就可以 使用传说中的C4收集器了。
  • 如果你虽然没有足够预算去使用商业解决方案,但能够掌控软硬件型号,使用较新的版本,同时 又特别注重延迟,那ZGC很值得尝试。
  • 如果你对还处于实验状态的收集器的稳定性有所顾虑,或者应用必须运行在Win-dows操作系统 下,那ZGC就无缘了,试试Shenandoah吧。
  • 如果你接手的是遗留系统,软硬件基础设施和JDK版本都比较落后,那就根据内存规模衡量一 下,对于大概4GB到6GB以下的堆内存,CMS一般能处理得比较好,而对于更大的堆内存,可重点考 察一下G1。

当然,以上都是仅从理论出发的分析,实战中切不可纸上谈兵,根据系统实际情况去测试才是选 择收集器的最终依据。

虚拟机及垃圾收集器日志

阅读分析虚拟机和垃圾收集器的日志是处理Java虚拟机内存问题必备的基础技能,垃圾收集器日 志是一系列人为设定的规则,多少有点随开发者编码时的心情而定,没有任何的“业界标准”可言,换 句话说,每个收集器的日志格式都可能不一样。除此以外还有一个麻烦,在JDK 9以前,HotSpot并没 有提供统一的日志处理框架,虚拟机各个功能模块的日志开关分布在不同的参数上,日志级别、循环 日志大小、输出格式、重定向等设置在不同功能上都要单独解决。直到JDK 9,这种混乱不堪的局面 才终于消失,HotSpot所有功能的日志都收归到了“-Xlog”参数上,这个参数的能力也相应被极大拓展 了:

-Xlog[:[selector][:[output][:[decorators][:output-options]]]]

命令行中最关键的参数是选择器(Selector),它由标签(Tag)和日志级别(Level)共同组成。 标签可理解为虚拟机中某个功能模块的名字,它告诉日志框架用户希望得到虚拟机哪些功能的日志输 出。垃圾收集器的标签名称为“gc”,由此可见,垃圾收集器日志只是HotSpot众多功能日志的其中一 项,全部支持的功能模块标签名如下所示:
add,age,alloc,annotation,aot,arguments,attach,barrier,biasedlocking,blocks,bot,breakpoint,bytecode,census,class,classhisto,cleanup,compaction,comparator,constraints,constantpool,coops,cpu,cset,data,defaultmethods,dump,ergo,event,exceptions,exit,fingerprint,freelist,gc,hashtables,heap,humongous,ihop,iklass,init,itables,jfr,jni,jvmti,liveness,load,loader,logging,mark,marking,metadata,metaspace,method,mmu,modules,monitorinflation,monitormismatch,nmethod,normalize,objecttagging,obsolete,oopmap,os,pagesize,parser,patch,path,phases,plab,preorder,promotion,protectiondomain,purge,redefine,ref,refine,region,remset,resolve,safepoint,scavenge,scrub,setting,stackmap,stacktrace,stackwalk,start,startuptime,state,stats,stringdedup,stringtable,subclass,survivor,sweep,system,task,thread,time,timer,tlab,unload,update,verification,verify,vmoperation,vtables,workgang

日志级别从低到高,共有Trace,Debug,Info,Warning,Error,Off六种级别,日志级别决定了输 出信息的详细程度,默认级别为Info,HotSpot的日志规则与Log4j、SLF4j这类Java日志框架大体上是 一致的。另外,还可以使用修饰器(Decorator)来要求每行日志输出都附加上额外的内容,支持附加 在日志行上的信息包括:

  • time:当前日期和时间。
  • uptime:虚拟机启动到现在经过的时间,以秒为单位。
  • timemillis:当前时间的毫秒数,相当于System.currentTimeMillis()的输出。
  • uptimemillis:虚拟机启动到现在经过的毫秒数。
  • timenanos:当前时间的纳秒数,相当于System.nanoTime()的输出。
  • uptimenanos:虚拟机启动到现在经过的纳秒数。
  • pid:进程ID。
  • tid:线程ID。
  • level:日志级别。
  • tags:日志输出的标签集。

如果不指定,默认值是uptime、level、tags这三个,此时日志输出类似于以下形式:
[3.080s][info][gc,cpu] GC(5) User=0.03s Sys=0.00s Real=0.01s

下面笔者举几个例子,展示在JDK 9统一日志框架前、后是如何获得垃圾收集器过程的相关信 息,以下均以JDK 9的G1收集器(JDK 9下默认收集器就是G1,所以命令行中没有指定收集器)为 例。

1)查看GC基本信息,在JDK 9之前使用-XX:+PrintGC,JDK 9后使用-Xlog:gc:

bash-3.2$ java -Xlog:gc GCTest

[0.222s][info][gc] Using G1
[2.825s][info][gc] GC(0) Pause Young (G1 Evacuation Pause) 26M->5M(256M) 355.623ms
[3.096s][info][gc] GC(1) Pause Young (G1 Evacuation Pause) 14M->7M(256M) 50.030ms
[3.385s][info][gc] GC(2) Pause Young (G1 Evacuation Pause) 17M->10M(256M) 40.576ms

2)查看GC详细信息,在JDK 9之前使用-XX:+PrintGCDetails,在JDK 9之后使用-X-log:gc*, 用通配符*将GC标签下所有细分过程都打印出来,如果把日志级别调整到Debug或者Trace(基于版面 篇幅考虑,例子中并没有),还将获得更多细节信息:

bash-3.2$ java -Xlog:gc* GCTest

[0.233s][info][gc,heap] Heap region size: 1M
[0.383s][info][gc ] Using G1
[0.383s][info][gc,heap,coops] Heap address: 0xfffffffe50400000, size: 4064 MB, Compressed Oops mode: Non-zero based: 0xfffffffe50000000, Oop shift amount: 3
[3.064s][info][gc,start ] GC(0) Pause Young (G1 Evacuation Pause) gc,task ] GC(0) Using 23 workers of 23 for evacuation
[3.420s][info][gc,phases ] GC(0) Pre Evacuate Collection Set: 0.2ms
[3.421s][info][gc,phases ] GC(0) Evacuate Collection Set: 348.0ms gc,phases ] GC(0) Post Evacuate Collection Set: 6.2ms
[3.421s][info][gc,phases ] GC(0) Other: 2.8ms gc,heap ] GC(0) Eden regions: 24->0(9)
[3.421s][info][gc,heap ] GC(0) Survivor regions: 0->3(3)
[3.421s][info][gc,heap ] GC(0) Old regions: 0->2
[3.421s][info][gc,heap ] GC(0) Humongous regions: 2->1
[3.421s][info][gc,metaspace ] GC(0) Metaspace: 4719K->4719K(1056768K)
[3.421s][info][gc ] GC(0) Pause Young (G1 Evacuation Pause) 26M->5M(256M) 357.743ms
[3.422s][info][gc,cpu ] GC(0) User=0.70s Sys=5.13s Real=0.36s
[3.648s][info][gc,start ] GC(1) Pause Young (G1 Evacuation Pause)
[3.648s][info][gc,task ] GC(1) Using 23 workers of 23 for evacuation
[3.699s][info][gc,phases ] GC(1) Pre Evacuate Collection Set: 0.3ms gc,phases ] GC(1) Evacuate Collection Set: 45.6ms gc,phases ] GC(1) Post Evacuate Collection Set: 3.4ms gc,phases ] GC(1) Other: 1.7ms gc,heap ] GC(1) Eden regions: 9->0(10)
[3.699s][info][gc,heap ] GC(1) Survivor regions: 3->2(2)
[3.699s][info][gc,heap ] GC(1) Old regions: 2->5
[3.700s][info][gc,heap ] GC(1) Humongous regions: 1->1
[3.700s][info][gc,metaspace ] GC(1) Metaspace: 4726K->4726K(1056768K)
[3.700s][info][gc ] GC(1) Pause Young (G1 Evacuation Pause) 14M->7M(256M) 51.872ms
[3.700s][info][gc,cpu ] GC(1) User=0.56s Sys=0.46s Real=0.05s

3)查看GC前后的堆、方法区可用容量变化,在JDK 9之前使用-XX:+PrintHeapAtGC,JDK 9之 后使用-Xlog:gc+heap=debug:

bash-3.2$ java -Xlog:gc+heap=debug GCTest

[0.113s][info][gc,heap] Heap region size: 1M
[0.113s][debug][gc,heap] Minimum heap 8388608 Initial heap 268435456 Maximum heap 4261412864
[2.529s][debug][gc,heap] GC(0) Heap before GC invocations=0 (full 0):
[2.529s][debug][gc,heap] GC(0) garbage-first heap total 262144K, used 26624K [0xfffffffe50400000, 0xfffffffe50500800, 0xffffffff4e400000)
[2.529s][debug][gc,heap] GC(0) region size 1024K, 24 young (24576K), 0 survivors (0K)
[2.530s][debug][gc,heap] GC(0) Metaspace used 4719K, capacity 4844K, committed 5120K, reserved 1056768K
[2.530s][debug][gc,heap] GC(0) class space used 413K, capacity 464K, committed 512K, reserved 1048576K
[2.892s][info ][gc,heap] GC(0) Eden regions: 24->0(9)
[2.892s][info ][gc,heap] GC(0) Survivor regions: 0->3(3)
[2.892s][info ][gc,heap] GC(0) Old regions: 0->2
[2.892s][info ][gc,heap] GC(0) Humongous regions: 2->1
[2.893s][debug][gc,heap] GC(0) Heap after GC invocations=1 (full 0):
[2.893s][debug][gc,heap] GC(0) garbage-first heap total 262144K, used 5850K [0xfffffffe50400000, 0xfffffffe50500800, 0xffffffff4e400000)
[2.893s][debug][gc,heap] GC(0) region size 1024K, 3 young (3072K), 3 survivors (3072K)
[2.893s][debug][gc,heap] GC(0) Metaspace used 4719K, capacity 4844K, committed 5120K, reserved 1056768K
[2.893s][debug][gc,heap] GC(0) class space used 413K, capacity 464K, committed 512K, reserved 1048576K

4)查看GC过程中用户线程并发时间以及停顿的时间,在JDK 9之前使用-XX:+Print- GCApplicationConcurrentTime以及-XX:+PrintGCApplicationStoppedTime,JDK 9之后使用-Xlog:safepoint:

bash-3.2$ java -Xlog:safepoint GCTest

[1.376s][info][safepoint] Application time: 0.3091519 seconds
[1.377s][info][safepoint] Total time for which application threads were stopped: 0.0004600 seconds, Stopping threads took: 0.0002648 seconds
[2.386s][info][safepoint] Application time: 1.0091637 seconds
[2.387s][info][safepoint] Total time for which application threads were stopped: 0.0005217 seconds, Stopping threads took: 0.0002297 seconds

5)查看收集器Ergonomics机制(自动设置堆空间各分代区域大小、收集目标等内容,从Parallel收 集器开始支持)自动调节的相关信息。在JDK 9之前使用-XX:+PrintAdaptive-SizePolicy,JDK 9之后 使用-Xlog:gc+ergo*=trace:

bash-3.2$ java -Xlog:gc+ergo*=trace GCTest

[0.122s][debug][gc,ergo,refine] Initial Refinement Zones: green: 23, yellow: 69, red: 115, min yellow size: 46
[0.142s][debug][gc,ergo,heap ] Expand the heap. requested expansion amount:268435456B expansion amount:268435456B
[2.475s][trace][gc,ergo,cset ] GC(0) Start choosing CSet. pending cards: 0 predicted base time: 10.00ms remaining time: 190.00ms target pause time: 200.00ms
[2.476s][trace][gc,ergo,cset ] GC(0) Add young regions to CSet. eden: 24 regions, survivors: 0 regions, predicted young region time: 367.19ms, target pause time: 200.00ms
[2.476s][debug][gc,ergo,cset ] GC(0) Finish choosing CSet. old: 0 regions, predicted old region time: 0.00ms, time remaining: 0.00
[2.826s][debug][gc,ergo ] GC(0) Running G1 Clear Card Table Task using 1 workers for 1 units of work for 24 regions.
[2.827s][debug][gc,ergo ] GC(0) Running G1 Free Collection Set using 1 workers for collection set length 24
[2.828s][trace][gc,ergo,refine] GC(0) Updating Refinement Zones: update_rs time: 0.004ms, update_rs buffers: 0, update_rs goal time: 19.999ms

6)查看熬过收集后剩余对象的年龄分布信息,在JDK 9前使用-XX:+PrintTenuring-Distribution, JDK 9之后使用-Xlog:gc+age=trace:

bash-3.2$ java -Xlog:gc+age=trace GCTest

[2.406s][debug][gc,age] GC(0) Desired survivor size 1572864 bytes, new threshold 15 (max threshold 15)
[2.745s][trace][gc,age] GC(0) Age table with threshold 15 (max threshold 15)
[2.745s][trace][gc,age] GC(0) - age 1: 3100640 bytes, 3100640 total
[4.700s][debug][gc,age] GC(5) Desired survivor size 2097152 bytes, new threshold 15 (max threshold 15)
[4.810s][trace][gc,age] GC(5) Age table with threshold 15 (max threshold 15)
[4.810s][trace][gc,age] GC(5) - age 1: 2658280 bytes, 2658280 total
[4.810s][trace][gc,age] GC(5) - age 2: 1527360 bytes, 4185640 total

囿于篇幅原因,不再一一列举,表3-3给出了全部在JDK 9中被废弃的日志相关参数及它们在JDK 9后使用-Xlog的代替配置形式。

表3-3JDK 9前后日志参数变化

JDK 9前日志参数 JDK 9后配置形式
G1PrintHeapRegions Xlog:gc+region=trace
G1PrintRegionLivenessInfo Xlog:gc+liveness=trace
G1SummarizeConcMark Xlog:gc+marking=trace
G1SummarizeRSetStats Xlog:gc+remset*=trace
GCLogFileSize,NumberOfGCLogFiles,UseGCLogFileRotation Xlog:gc*:file=<file>::filecount=<count>,filesize=<file size in kb>
PrintAdaptiveSizePolicy Xlog:gc+ergo*=trace
PrintClassHistogramAfterFullGC Xlog:classhisto*-trace
PrintClassHistogramBeforeFullGC Xlog:classhisto*=trace
PrintGCApplicationConcurrentTime Xlog:safepoint
PrintGCApplicationStoppedTime Xlog:safepoint
PrintGCDateStamps 使用time修饰器
PrintGCTaskTimeStamps Xlog:gc+task=trace
PrintGCTimeStamps 使用uptime修饰器
PrintHeapAtGC Xlog:gc+heap=debug
PrintHeapAtGCExtended Xlog:gc+heap=trace
PrintJNIGCStalls Xlog:gc+jni=debug
PrintOldPLAB Xlog:gc+plab=trace
PrintParallelOldGCPhaseTimes Xlog:gc+phases=trace
PrintPLAB Xlog:gc+plab=trace
PrintPromotionFailure Xlog:gc+promotion=debug
PrintReferenceGC Xlog:gc+ref=debug
PrintStringDeduplicationStatistics Xlog:gc+stringdedup
PrintTaskqueue Xlog:gc+task+stats=trace
PrintTenuringDistribution Xlog:ge+age=trace
PrintTerminationStats Xlog:gc+task+stats=debug
PrintTLAB Xlog:gc+tlab=trace
TraceAdaptiveGCBoundary Xlog:heap+ergo=debug
TraceDynamicGCThreads Xlog:gc+task=trace
TraceMetadataHumongousAllocation Xlog:gc+metaspace+alloc=debug
GlTraceConcRefinement Xlog:gc+refine=debug
GlTraceEagerReclaimHumongousObjects Xlog:gc+humongous=debug
GlTraceStringSymbolTableScrubbing Xlog:ge+stringtable=trace

垃圾收集器参数总结

HotSpot虚拟机中的各种垃圾收集器到此全部介绍完毕,在描述过程中提到了很多虚拟机非稳定的 运行参数,下面表3-4中整理了这些参数,供读者实践时参考。

参数 描述
UseSerialGC 虚拟机运行在Client模式下的默认值, 打开此开关后, 使用Serial+Serial Old的收集器组合进行内存回收
UseParNewGC 打开此开关后, 使用Par New+Serial Old的收集器组合进行内存回收, 在JDK 9后不再支持
UseConcMarkSweepGC 打开此开关后, 使用ParNew+CMS+Serial Old的收集器组合进行内存回收。Serial Old收集器将作为CMS收集器出现“Concurrent Mode Failure”失败后的后备收集器使用
UseParallelGC JDK 9之前虚拟机运行在Server模式下的默认值, 打开此开关后, 使用Parallel Scavenge+Serial Old(PS Mark Sweep) 的收集器组合进行内存回收
UseParallelOldGC 打开此开关后, 使用Parallel Scavenge+Parallel Old的收集器组合进行内存回收
SurvivorRatio 新生代中Eden区域与Survivor区域的容量比值, 默认为8, 代表Eden:Survivor=8:1
PretenureSizeThreshold 直接晋升到老年代的对象大小,设置这个参数后,大于这个参数的对象将直接在老年代分配
MaxTenuringThreshold 晋升到老年代的对象年龄。每个对象在坚持过一次Minor GC之后, 年龄就增加1,当超过这个参数值时就进人老年代
UseAdaptiveSizePolicy 动态调整Java堆中各个区域的大小以及进人老年代的年龄
HandlePromotionFailure 是否允许分配担保失败,即老年代的剩余空间不足以应付新生代的整个Eden和Survivor区的所有对象都存活的极端情况
ParallelGCThreads 设置并行GC时进行内存回收的线程数
GCTimeRatio GC时间占总时间的比率,默认值为99,即允许1%的GC时间。仅在使用Parallel Scavenge收集器时生效
MaxGCPauseMillis 设置GC的最大停顿时间。仅在使用Parallel Scavenge收集器时生效
CMSInitiatingOccupancyFraction 设置CMS收集器在老年代空间被使用多少后触发垃圾收集。默认值为68%, 仅在使用CMS收集器时生效
UseCMSCompactAtFullCollection 设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片整理。仅在使用CMS收集器时生效, 此参数从JDK 9开始废弃
CMSFullGCsBeforeCompaction 设置CMS收集器在进行若干次垃圾收集后再启动一次内存碎片整理。仅在使用CMS收集器时生效, 此参数从JDK 9开始废弃
UseG1GC 使用G 1收集器, 这个是JDK 9后的Server模式默认值
G1HeapRegionSize=n 设置Region大小, 并非最终值
MaxGCPauseMillis 设置G1收集过程目标时间,默认值是200ms,不是硬性条件
G1NewSizePercent 新生代最小值,默认值是5%
G1MaxNewSizePercent 新生代最大值,默认值是60%
ParallelGCThreads 用户线程冻结期间并行执行的收集器线程数

选择合适的垃圾收集器相关推荐

  1. JAVA选择合适的垃圾收集器+内存分配实战

    <深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)> 目录 低延迟垃圾收集器 Shenandoah收集器 ZGC收集器 选择合适的垃圾收集器 Epsilon收集器 收集器的权衡 ...

  2. 如何选择合适的垃圾收集器

    官网:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html#sthref28 优先调整堆 ...

  3. JVM垃圾收集—垃圾收集器及常见组合参数

    链接: JVM垃圾收集-垃圾收集算法 上一篇介绍了垃圾收集算法及分区,这篇我们来学习垃圾收集器 文章目录 Serial ParNew Parallel Scavenge Serial Old Para ...

  4. JVM:自动内存管理-垃圾收集器与内存分配策略

    Java与C++之间有一堵由内存分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 一.概述 Java堆和方法区这两个区域有着很显著的不确定性: 1.一个接口的多个实现类需要的内存 ...

  5. 第3章 垃圾收集器与内存分配策略6

    3.7 选择合适的垃圾收集器 HotSpot虚拟机提供了种类繁多的垃圾收集器,选择太多反而令人踌躇难决,若只挑最先进的显然不可能满足全部应用场景,但只用一句"必须因地制宜,按需选用" ...

  6. 第3章 垃圾收集器与内存分配策略

    book:<深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)周志明> 文章目录 3.1 概述 3.2 对象已死? 3.2.1 引用计数算法 3.2.2 可达性分析算法(根搜索算法 ...

  7. JVM——》G1垃圾收集器

    一.概念 参考链接:   garbage-first 发展过程: 1.7 出现 1.8 推荐使用 1.9 默认使用 1.特点 1)分代收集(逻辑分代) 2)空间整合(整体上属于"标记-整理& ...

  8. JVM - 再聊GC垃圾收集算法及垃圾收集器

    文章目录 Pre 分代收集理论 常见的垃圾收集算法 标记-清除算法 标记-复制算法 标记-整理算法 垃圾收集器 Serial收集器 Parallel Scavenge收集器 [JDK8默认] ParN ...

  9. 七种垃圾收集器和垃圾回收、分代收集、GCROOTS相关概念、GC如何判断一个对象可以被回收

    文章目录 垃圾收集器概述 垃圾回收算法 1)标记-清除算法(Mark-Sweep)(DVM 使用的算法) 2)复制算法(Copying) 3)标记-整理算法(Mark-Compact) 4)分代收集( ...

最新文章

  1. linux 进程 控制终端,linux系统编程之进程(五):终端、作业控制与守护进程
  2. Day5:python之函数(3)
  3. 5.4 Spring AOP
  4. 利用numpy删除DataFrame某一行/列、多行内容
  5. 当我们群嘲假博士时,不要忘了真博士们的艰辛
  6. SQL注入:2、读写文件和下载数据库
  7. CNCC2018:[早鸟票]倒计时两周,7000人盛会日程抢先看!
  8. win7安装mysql8.0.15教程_MySQL-mysql 8.0.15安装教程
  9. Spring中Bean的作用域差别
  10. 中国水电基础局携手友勤开展2018年P6软件培训班
  11. php 真太阳时间修正,全国真太阳时对照表
  12. 網頁設計收藏站70個
  13. H5 简单实现微信公众号摇一摇功能
  14. openwrt USB热插拔(hotplug)
  15. 简易的微信公众号管理平台使用指南
  16. 前端项目实战11-hook usememo使用
  17. 以Crotex M3为例讲解stm32芯片内部原理
  18. matlab音频信号导入,如何将语音信号导入simulink中
  19. JVM常见命令行及图形工具
  20. 关于BHO不能够正常运行的问题!

热门文章

  1. 钉钉免费实现内网穿透绝对靠谱
  2. BBS(仿博客园系统)项目03(主页搭建、个人站点搭建(侧边栏分类展示、标签展示、日期归档)、文章详情页相关功能实现)...
  3. 垃圾回收器——CMS与G1
  4. 获取复选框的被选中的值
  5. 快速学会3DMax高级建模人物骨骼蒙皮
  6. vue项目将px转为rem实践
  7. gnuplot小功能
  8. 照片尺寸是假像素对照表
  9. 推荐几款HTML5开发工具
  10. 设计模式01---设计模式基础篇01