<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Jvm on Liangweidong's blog</title><link>https://liangweidonggood.github.io/tags/jvm/</link><description>Recent content in Jvm on Liangweidong's blog</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Tue, 06 Mar 2018 00:00:00 +0000</lastBuildDate><atom:link href="https://liangweidonggood.github.io/tags/jvm/index.xml" rel="self" type="application/rss+xml"/><item><title>JVM调优常用参数</title><link>https://liangweidonggood.github.io/p/04-jvm-tiao-you-chang-yong-can-shu/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/04-jvm-tiao-you-chang-yong-can-shu/</guid><description>&lt;h2 id="214-jvm调优常用参数"&gt;§2.1.4 JVM调优常用参数
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：能否根据实际场景选择合适的JVM参数，而非无脑复制粘贴。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;基础内存参数&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;参数&lt;/th&gt;
					&lt;th&gt;含义&lt;/th&gt;
					&lt;th&gt;常见设置&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;-Xms&lt;/code&gt; / &lt;code&gt;-Xmx&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;初始/最大堆大小&lt;/td&gt;
					&lt;td&gt;建议设为相同值，避免堆动态扩缩带来的GC抖动。4G服务通常 &lt;code&gt;-Xms4g -Xmx4g&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;-Xss&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;线程栈大小&lt;/td&gt;
					&lt;td&gt;默认1MB。线程数多且调用栈浅可缩小（512k），递归深可加大&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;-XX:NewRatio&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;老年代:新生代比例&lt;/td&gt;
					&lt;td&gt;默认2（Old=堆的2/3，Young=1/3）。高并发短命对象可调为1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;-XX:SurvivorRatio&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Eden:Survivor比例&lt;/td&gt;
					&lt;td&gt;默认8（Eden:S0:S1=8:1:1）。大多数场景不需改&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;-XX:MaxTenuringThreshold&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;晋升老年代年龄阈值&lt;/td&gt;
					&lt;td&gt;默认15（CMS默认6）。值小则对象快速晋升但可能过早填满老年代&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;-XX:MetaspaceSize&lt;/code&gt; / &lt;code&gt;-XX:MaxMetaspaceSize&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;元空间初始/最大大小&lt;/td&gt;
					&lt;td&gt;默认无上限（受物理内存限制）。动态生成类多的场景建议设上限防泄漏。典型256m-512m&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;GC日志参数&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# JDK 8 经典三件套&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/path/to/gc.log
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-XX:+PrintHeapAtGC &lt;span class="c1"&gt;# GC前后打印堆快照（排查内存泄漏利器）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-XX:+PrintTenuringDistribution &lt;span class="c1"&gt;# 打印各年龄段的存活对象分布&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# JDK 9+ 统一日志&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-Xlog:gc*&lt;span class="o"&gt;=&lt;/span&gt;info:file&lt;span class="o"&gt;=&lt;/span&gt;/path/to/gc.log:time,level,tags:filecount&lt;span class="o"&gt;=&lt;/span&gt;10,filesize&lt;span class="o"&gt;=&lt;/span&gt;100M
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# gc* 表示所有GC相关日志，info级别，滚动10个文件每个100MB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;OOM排查必开&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;参数&lt;/th&gt;
					&lt;th&gt;作用&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;-XX:+HeapDumpOnOutOfMemoryError&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;OOM时自动dump堆快照，&lt;strong&gt;生产环境必须开&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;-XX:HeapDumpPath=/path/to/dumps&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;dump文件路径，防止撑爆根目录&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;-XX:OnOutOfMemoryError=&amp;quot;kill -9 %p&amp;quot;&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;OOM时执行自定义命令（注意安全隐患）&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;G1调优参数&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;参数&lt;/th&gt;
					&lt;th&gt;含义&lt;/th&gt;
					&lt;th&gt;建议&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;-XX:MaxGCPauseMillis&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;期望最大停顿时间&lt;/td&gt;
					&lt;td&gt;默认200ms，不要设太低（比如10ms）——G1达不到会疯狂GC反而性能下降。服务端通常50-200ms&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;-XX:G1HeapRegionSize&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Region大小&lt;/td&gt;
					&lt;td&gt;默认堆/2048，取值1/2/4/8/16/32M。大对象多可调大&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;-XX:ConcGCThreads&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;并发GC线程数&lt;/td&gt;
					&lt;td&gt;默认≈CPU核数的1/4。CPU资源紧张时减半&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;-XX:InitiatingHeapOccupancyPercent&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;触发并发标记的堆占用阈值&lt;/td&gt;
					&lt;td&gt;默认45%。堆占用达此值触发并发标记周期。值设太低频繁GC浪费CPU，太高预留不够触发Full GC&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;真实配置示例——安全生产平台（JDK 8, 4核8G）&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-Xms4g -Xmx4g
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-XX:+UseG1GC
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-XX:MaxGCPauseMillis&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-XX:G1HeapRegionSize&lt;span class="o"&gt;=&lt;/span&gt;4m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-XX:MetaspaceSize&lt;span class="o"&gt;=&lt;/span&gt;256m -XX:MaxMetaspaceSize&lt;span class="o"&gt;=&lt;/span&gt;512m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-XX:+HeapDumpOnOutOfMemoryError
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-XX:HeapDumpPath&lt;span class="o"&gt;=&lt;/span&gt;/data/logs/dumps
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/data/logs/gc-%t.log
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt; -XX:GCLogFileSize&lt;span class="o"&gt;=&lt;/span&gt;50M
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：把线上配置直接复制粘贴但说不清每个参数的业务取舍原因；设 &lt;code&gt;MaxGCPauseMillis=10&lt;/code&gt;显得不专业；不知道生产环境必须开HeapDumpOnOutOfMemoryError。&lt;/p&gt;</description></item><item><title>JVM调优工具实战</title><link>https://liangweidonggood.github.io/p/05-jvm-tiao-you-gong-ju-shi-zhan/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/05-jvm-tiao-you-gong-ju-shi-zhan/</guid><description>&lt;h2 id="215-jvm调优工具实战"&gt;§2.1.5 JVM调优工具实战
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：能否独立的在生产环境排查问题，使用合适的工具定位根因。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Arthas——线上诊断神器&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;阿里开源的Java诊断工具，零侵入，直接attach到运行中的Java进程，线上排查首选。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 启动&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;java -jar arthas-boot.jar
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 选择目标Java进程即可&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 最常用命令&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dashboard &lt;span class="c1"&gt;# 实时看板：线程/内存/GC/CPU&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;thread -n &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="c1"&gt;# CPU最高的5个线程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;thread -b &lt;span class="c1"&gt;# 找出死锁&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jad com.xx.MyService &lt;span class="c1"&gt;# 反编译已加载的类，验证线上版本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;watch com.xx.MyService myMethod &lt;span class="s2"&gt;&amp;#34;{params,returnObj,throwExp}&amp;#34;&lt;/span&gt; -x &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# 监控方法入参/出参/异常&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;trace com.xx.MyService myMethod -n &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="c1"&gt;# 追踪方法调用链路，找出哪个子步骤耗时最长&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tt -t com.xx.MyService myMethod &lt;span class="c1"&gt;# 记录方法调用（TimeTunnel），支持重放&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmoption &lt;span class="c1"&gt;# 查看JVM参数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmtool --action getInstances -c com.xx.MyClass --limit &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="c1"&gt;# 获取堆中某类实例&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;monitor -c &lt;span class="m"&gt;5&lt;/span&gt; com.xx.MyService myMethod &lt;span class="c1"&gt;# 监控方法调用次数/成功率/平均耗时&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;实际场景&lt;/strong&gt;：一次线上接口变慢，用Arthas的trace一追踪，发现是下游规则引擎的Drools session创建占了80%耗时——KieSession没做池化每次new一个。加了KieSession对象池后恢复。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;JDK自带工具——四件套&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# jps —— 列出Java进程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jps -lv &lt;span class="c1"&gt;# 列出所有Java进程，显示JVM参数和main类&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# jstat —— JVM统计监控（实时看GC）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jstat -gcutil PID &lt;span class="m"&gt;1000&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="c1"&gt;# 每秒打印一次GC统计，共10次&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 输出关键列：S0/S1(Eden+Survivor使用率), E(eden), O(old), M(metaspace), YGC/YGCT(youngGC次数/耗时), FGC/FGCT(fullGC)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 解读：FGC频繁 + FGCT高 → 老年代不足或内存泄漏&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# E接近100%然后骤降 → 正常Minor GC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# O持续增长不降 → 内存泄漏信号&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# jmap —— 堆内存分析&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jmap -heap PID &lt;span class="c1"&gt;# 堆内存概览（各区域大小和使用率）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jmap -histo:live PID &lt;span class="p"&gt;|&lt;/span&gt; head -20 &lt;span class="c1"&gt;# 堆中存活对象统计（top 20，强制执行一次Full GC）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jmap -dump:format&lt;span class="o"&gt;=&lt;/span&gt;b,file&lt;span class="o"&gt;=&lt;/span&gt;heap.hprof PID &lt;span class="c1"&gt;# 堆dump（生产慎用，会STW）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# jstack —— 线程堆栈分析&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jstack PID &amp;gt; thread.log &lt;span class="c1"&gt;# 打印线程堆栈&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jstack -l PID &lt;span class="c1"&gt;# 额外打印锁信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# grep查找：BLOCKED（锁等待）/ WAITING（等待唤醒）/ TIMED_WAITING（超时等待）/ RUNNABLE（正在执行）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 看线程名：如果全是http-nio-xxx-WAITING → 数据库或下游服务慢&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;MAT（Memory Analyzer Tool）——堆dump分析&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 先用 jmap dump 堆快照，然后用MAT打开分析&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# MAT直接点&amp;#34;Leak Suspects Report&amp;#34; → 自动分析内存泄漏嫌疑&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 核心操作：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1. Histogram：按类统计对象数量和内存占用，找大对象&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 2. Dominator Tree：支配树——最大的内存持有者&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 3. Path to GC Roots：某个对象为什么没被回收（引用链追溯到GC Root）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;实际场景&lt;/strong&gt;：OOM排查，MAT打开dump→ Dominator Tree发现HashMap占3.2GB→ Path to GC Roots找到是定时任务的全量缓存→改成分页+本地缓存解决。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;jinfo——查看/修改JVM运行时参数&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jinfo -flags PID &lt;span class="c1"&gt;# 查看所有参数（包括默认值）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jinfo -flag +PrintGC PID &lt;span class="c1"&gt;# 运行时动态开启GC日志（部分参数支持动态修改）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;生产环境排查最佳路径&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;遇到CPU飙升 → Arthas &lt;code&gt;dashboard&lt;/code&gt; + &lt;code&gt;thread -n 5&lt;/code&gt; → 定位到具体线程 → &lt;code&gt;jad&lt;/code&gt;反编译验证 → 改代码&lt;/li&gt;
&lt;li&gt;遇到内存泄漏 → &lt;code&gt;jstat -gcutil&lt;/code&gt;观察O区持续增长 → &lt;code&gt;jmap -dump&lt;/code&gt; → MAT分析Dominator Tree → Path to GC Roots → 改代码&lt;/li&gt;
&lt;li&gt;遇到死锁 → &lt;code&gt;jstack -l&lt;/code&gt; → 搜DEADLOCK → 或Arthas &lt;code&gt;thread -b&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;遇到接口变慢 → Arthas &lt;code&gt;trace&lt;/code&gt; → 定位最耗时的子调用 → 深入分析&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：只会用jps/jstat但说不清每列含义；线上 &lt;code&gt;jmap -dump&lt;/code&gt;不提醒STW风险；不知道Arthas的attach机制（VirtualMachine.attach不需要Agent）。&lt;/p&gt;</description></item><item><title>JVM调优实战案例</title><link>https://liangweidonggood.github.io/p/06-jvm-tiao-you-shi-zhan-an-li/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/06-jvm-tiao-you-shi-zhan-an-li/</guid><description>&lt;h2 id="216-jvm调优实战案例"&gt;§2.1.6 JVM调优实战案例
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：验证完整的排查→定位→解决→验证闭环能力。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;案例一：定时任务导致Full GC&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;危废平台上线后，每周固定时间接口响应从200ms飙升到5秒以上。排查：&lt;code&gt;jstat -gcutil&lt;/code&gt;看发现老年代每周末凌晨突增 → &lt;code&gt;jmap -dump&lt;/code&gt;堆内存用MAT分析 → Dominator Tree发现HashMap缓了几百万条危废联单数据 → 根因是定时任务没做分页，一次load全量数据。解决方案不是调JVM参数，而是改代码——Caffeine本地缓存（最大条目+过期时间），定时任务改分批。改完后Full GC停顿从1.2秒降到100ms以内。教训：JVM调优很多时候改代码比改参数更有效。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;案例二：Metaspace溢出&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;生产环境切流量后运行12小时左右突然 &lt;code&gt;OOM: Metaspace&lt;/code&gt;。排查：&lt;code&gt;jstat -gcutil&lt;/code&gt;看MU（Metaspace使用率）接近100% → &lt;code&gt;jmap -clstats&lt;/code&gt;看加载的类数量异常高（正常几千，它几百万）→ Arthas &lt;code&gt;vmtool&lt;/code&gt;查看发现大量 &lt;code&gt;com.sun.proxy.$ProxyXXX&lt;/code&gt;类 → 定位到Groovy脚本引擎每次执行规则都 &lt;code&gt;new GroovyClassLoader()&lt;/code&gt;但没关 → ClassLoader泄漏导致反复加载同类→ Metaspace撑爆。解决：GroovyClassLoader改单例复用，加 &lt;code&gt;-XX:MaxMetaspaceSize=256m&lt;/code&gt;兜底限流。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;案例三：G1停顿时间优化&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;G1 GC后P99延迟偶尔飙到800ms。排查GC日志发现Mixed GC的Cleanup阶段耗时400ms——老年代Region中大对象过多。&lt;code&gt;-XX:G1HeapRegionSize&lt;/code&gt;从2MB调到4MB（让大对象进Humongous Region而非普通Old Region），加上 &lt;code&gt;-XX:+ParallelRefProcEnabled&lt;/code&gt;并行处理Reference对象，&lt;code&gt;-XX:MaxGCPauseMillis=100&lt;/code&gt;让G1自动收紧回收范围。优化后P99压到300ms以内。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：只讲成功案例不讲失败教训；编造数据（面试官可能现场让你画内存布局图）。&lt;/p&gt;</description></item><item><title>JVM类型对比（HotSpot / OpenJ9 / GraalVM）</title><link>https://liangweidonggood.github.io/p/07-jvm-lei-xing-dui-bi/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/07-jvm-lei-xing-dui-bi/</guid><description>&lt;h2 id="217-jvm类型对比hotspot--openj9--graalvm"&gt;§2.1.7 JVM类型对比（HotSpot / OpenJ9 / GraalVM）
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：是否了解JVM生态的多样性，能根据场景推荐合适的JVM实现。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;主流JVM实现有三个阵营：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HotSpot VM——Oracle/OpenJDK默认，绝对主流&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;市场份额：Java服务端90%+在用&lt;/li&gt;
&lt;li&gt;核心优势：**C2编译器（Server Compiler）**做了二十多年极致优化，逃逸分析、内联、循环优化极其成熟；&lt;strong&gt;G1/ZGC&lt;/strong&gt;等现代回收器最先落地；生态最完整&lt;/li&gt;
&lt;li&gt;JDK 8起HotSpot与JRockit合并，吸收了JRockit的Mission Control、Flight Recorder（JFR）等运维工具&lt;/li&gt;
&lt;li&gt;劣势：启动慢、内存占用高——Spring Boot应用空跑也要200MB+堆。不适合短生命周期场景（Serverless、FaaS）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;OpenJ9（Eclipse OpenJ9）——IBM捐献，低内存场景&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;前身是IBM J9 VM，2017年捐给Eclipse基金会&lt;/li&gt;
&lt;li&gt;核心优势：&lt;strong&gt;极低内存占用&lt;/strong&gt;——同等应用比HotSpot少30-50%内存；启动速度快；&lt;strong&gt;Shared Classes Cache（SCC）&lt;/strong&gt;——AOT编译缓存，多次启动复用编译结果&lt;/li&gt;
&lt;li&gt;垃圾回收：GenCon（分代并发，类似G1）+ Balanced（针对大堆）+ Metronome（实时GC，可配置停顿上限）&lt;/li&gt;
&lt;li&gt;劣势：生态和工具链不如HotSpot完善，部分框架兼容性问题；G1/ZGC等效方案不如HotSpot成熟&lt;/li&gt;
&lt;li&gt;适用场景：云原生/Serverless（启动快、内存省）、微服务容器化部署（每个Pod省200MB很可观）、嵌入式设备&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;GraalVM——多语言+AOT编译&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Oracle实验室项目，定位是&amp;quot;通用虚拟机&amp;quot;——不止跑Java，还能跑JavaScript、Python、Ruby、R、WASM&lt;/li&gt;
&lt;li&gt;两大杀手级特性：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Native Image（AOT编译）&lt;/strong&gt;：将Java应用编译为独立二进制，毫秒级启动、内存占用几十MB，非常适合Serverless和容器化。Spring Boot 3.0+官方支持GraalVM Native Image&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Truffle框架&lt;/strong&gt;：多语言互调用，Java代码直接调Python/JS函数，零JNI开销&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;两种模式：Community Edition（免费，Native Image支持有限）+ Enterprise Edition（收费，Native Image+PGO优化+多语言商业支持）&lt;/li&gt;
&lt;li&gt;劣势：AOT编译限制——限制反射/动态代理/动态类加载（需要配置 &lt;code&gt;reflect-config.json&lt;/code&gt;等元数据）；编译时间长（小项目几分钟，大项目几十分钟）；闭包分析可能漏掉运行时动态行为导致编译失败&lt;/li&gt;
&lt;li&gt;适用场景：Serverless/FaaS（毫秒级冷启动）、CLI工具、嵌入式、微服务容器镜像瘦身&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;场景选型速览&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;场景&lt;/th&gt;
					&lt;th&gt;推荐JVM&lt;/th&gt;
					&lt;th&gt;原因&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;传统服务端/企业应用&lt;/td&gt;
					&lt;td&gt;HotSpot&lt;/td&gt;
					&lt;td&gt;生态成熟、性能最稳定、GC方案最丰富&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;云原生/容器化微服务&lt;/td&gt;
					&lt;td&gt;OpenJ9 或 GraalVM&lt;/td&gt;
					&lt;td&gt;内存省、启动快、镜像小&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Serverless/FaaS&lt;/td&gt;
					&lt;td&gt;GraalVM Native Image&lt;/td&gt;
					&lt;td&gt;毫秒启动、极低内存&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;多语言混合项目&lt;/td&gt;
					&lt;td&gt;GraalVM Truffle&lt;/td&gt;
					&lt;td&gt;Java+Python/JS/R互调&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;嵌入式/IoT&lt;/td&gt;
					&lt;td&gt;OpenJ9&lt;/td&gt;
					&lt;td&gt;内存占用可控&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;实时响应（金融/交易）&lt;/td&gt;
					&lt;td&gt;HotSpot + ZGC&lt;/td&gt;
					&lt;td&gt;亚毫秒停顿&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：只知道HotSpot不知道有其他JVM实现；把GraalVM说成&amp;quot;就是编译成二进制的&amp;quot;忽略了多语言和Truffle；不知道GraalVM Native Image的限制（反射配置、编译时间）。&lt;/p&gt;</description></item><item><title>JVM内存模型</title><link>https://liangweidonggood.github.io/p/01-jvm-nei-cun-mo-xing/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/01-jvm-nei-cun-mo-xing/</guid><description>&lt;h2 id="211-jvm内存模型"&gt;§2.1.1 JVM内存模型
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：是否理解各内存区域的职责、存储内容、以及OOM的发生场景。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;JVM运行时数据区分为&lt;strong&gt;线程私有&lt;/strong&gt;和&lt;strong&gt;线程共享&lt;/strong&gt;两大类，共5个核心区域：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;区域&lt;/th&gt;
					&lt;th&gt;共享性&lt;/th&gt;
					&lt;th&gt;存储内容&lt;/th&gt;
					&lt;th&gt;OOM场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;程序计数器&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;线程私有&lt;/td&gt;
					&lt;td&gt;当前线程执行的字节码行号指示器&lt;/td&gt;
					&lt;td&gt;唯一不会OOM的区域&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;虚拟机栈&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;线程私有&lt;/td&gt;
					&lt;td&gt;栈帧（局部变量表+操作数栈+动态链接+返回地址）&lt;/td&gt;
					&lt;td&gt;线程过多或递归过深：StackOverflowError&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;本地方法栈&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;线程私有&lt;/td&gt;
					&lt;td&gt;Native方法的栈帧&lt;/td&gt;
					&lt;td&gt;与虚拟机栈类似&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;堆（Heap）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;线程共享&lt;/td&gt;
					&lt;td&gt;对象实例、数组&lt;/td&gt;
					&lt;td&gt;对象过多且GC无法回收：java.lang.OutOfMemoryError: Java heap space&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;方法区（元空间）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;线程共享&lt;/td&gt;
					&lt;td&gt;类元数据、静态变量、常量池、JIT编译缓存&lt;/td&gt;
					&lt;td&gt;动态生成类过多或常量池溢出：OOM: Metaspace&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;JDK 8关键变化——永久代→元空间&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;JDK 7及之前，方法区用永久代（PermGen）实现，属于JVM堆内存的一部分，受&lt;code&gt;-XX:MaxPermSize&lt;/code&gt;限制。JDK 8移除了永久代，改用本地内存中的&lt;strong&gt;元空间（Metaspace）&lt;/strong&gt;，默认只受物理内存限制。好处：之前永久代大小难以预估（加载的类数量不确定），经常导致&lt;code&gt;OOM: PermGen space&lt;/code&gt;。改用元空间后，类元数据放在堆外的本地内存，容量弹性更大。但风险是——如果不设&lt;code&gt;-XX:MaxMetaspaceSize&lt;/code&gt;，动态类加载失控会吃光物理内存。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;堆内存分代结构&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌───────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 堆 (Heap) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─────────────────┬─────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 新生代(Young) │ 老年代(Old) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ┌────┬────┬───┐│ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │Eden│ S0 │ S1││ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ 8 │ 1 │ 1 ││ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └────┴────┴───┘│ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 默认比例 8:1:1 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─────────────────┴─────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 新生代:老年代 ≈ 1:2 (默认 NewRatio=2) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└───────────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;新生代&lt;/strong&gt;：新创建的对象。Eden区（80%）+ Survivor 0（10%）+ Survivor 1（10%）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;老年代&lt;/strong&gt;：长期存活对象。经历多次Minor GC仍存活的对象晋升至此&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对象晋升流程&lt;/strong&gt;：Eden分配 → 首次Minor GC存活进S区 → 每次Minor GC存活Age+1 → Age达到&lt;code&gt;MaxTenuringThreshold&lt;/code&gt;（默认15）→ 晋升老年代。动态年龄判定：S区中同龄对象总大小超过S区50%时，该年龄及以上对象直接晋升&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;为什么需要两个Survivor区？&lt;/strong&gt; 解决内存碎片化——每次Minor GC，将Eden+From Survivor存活对象copy到To Survivor，然后清空Eden和From，From和To角色互换。始终保持一块Survivor为空，避免碎片化。这就是&lt;strong&gt;复制算法&lt;/strong&gt;在新生代的落地。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：说不清各个区域存什么；把方法区和元空间等同（元空间是实现，方法区是规范）；不知道永久代→元空间的JDK 8变化。&lt;/p&gt;</description></item><item><title>垃圾回收算法</title><link>https://liangweidonggood.github.io/p/02-la-ji-hui-shou-suan-fa/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/02-la-ji-hui-shou-suan-fa/</guid><description>&lt;h2 id="212-垃圾回收算法"&gt;§2.1.2 垃圾回收算法
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：理解各算法的原理、优缺点和适用分代，能结合业务场景说明选型理由。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;四种基础算法，JVM根据分代特性组合使用：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 标记-清除（Mark-Sweep）——最基础&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;流程：标记阶段遍历GC Roots标记存活对象 → 清除阶段回收未标记对象&lt;/li&gt;
&lt;li&gt;优点：算法简单，不移动对象&lt;/li&gt;
&lt;li&gt;缺点：&lt;strong&gt;内存碎片化&lt;/strong&gt;——清除后产生大量不连续的空闲内存。碎片严重时，即使总空闲内存足够，也可能无法分配大对象，触发Full GC&lt;/li&gt;
&lt;li&gt;适用：老年代的基础算法（CMS的标记-清除阶段）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. 标记-复制（Mark-Copy）——新生代首选&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;流程：将存活对象复制到另一块空白区域 → 原区域整块清空&lt;/li&gt;
&lt;li&gt;优点：无内存碎片，整块清空效率极高，只需移动存活对象&lt;/li&gt;
&lt;li&gt;缺点：浪费50%空间（需要一块空白区域做副本）。不过新生代对象98%朝生夕死，实际只需要很小的Survivor空间&lt;/li&gt;
&lt;li&gt;适用：&lt;strong&gt;新生代Minor GC&lt;/strong&gt;。8:1:1的Eden:Survivor比例就是基于这个假设——Survivor只需要留新生代10%的空间。如果Survivor不够放存活对象，通过&lt;strong&gt;分配担保机制&lt;/strong&gt;直接晋升老年代&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. 标记-整理（Mark-Compact）——老年代兜底&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;流程：标记存活对象 → 将所有存活对象移到内存一端 → 清理边界外的内存&lt;/li&gt;
&lt;li&gt;优点：无内存碎片，不需要浪费额外空间&lt;/li&gt;
&lt;li&gt;缺点：移动对象需要STW，且需要更新所有指向被移动对象的引用——停顿时间与堆中存活对象数量成正比&lt;/li&gt;
&lt;li&gt;适用：老年代（Serial Old、Parallel Old）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4. 分代收集（Generational Collection）——JVM的顶层策略&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不是独立算法，而是&amp;quot;不同分代用不同算法&amp;quot;的策略组合&lt;/li&gt;
&lt;li&gt;核心假设：&lt;strong&gt;弱分代假说&lt;/strong&gt;——绝大多数对象朝生夕死（新生代用复制算法）；&lt;strong&gt;强分代假说&lt;/strong&gt;——熬过多次GC的对象一般不会轻易死亡（老年代用标记-清除/标记-整理）&lt;/li&gt;
&lt;li&gt;几乎所有JVM垃圾回收器都基于分代假设设计&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;记忆集（Remembered Set）与卡表（Card Table）&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;分代收集的致命问题：&lt;strong&gt;跨代引用&lt;/strong&gt;。新生代对象被老年代引用时，Minor GC只扫新生代，无法通过GC Roots找到这个老年代引用，导致存活新生代对象被误清。解决方案：老年代维护一张&lt;strong&gt;卡表&lt;/strong&gt;——将老年代内存按512字节分块（Card），有老年代引用指向新生代时，对应Card标记为&amp;quot;脏&amp;quot;。Minor GC扫描时除了GC Roots还扫描卡表中的脏Card，避免全堆扫描。CMS和G1都在写屏障（Write Barrier）中维护这张卡表，性能开销约5%-10%。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：四种算法的优缺点和应用分代背串；不知道跨代引用问题和卡表机制；以为复制算法就是新生代的全部。&lt;/p&gt;</description></item></channel></rss>