<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>编程 on Liangweidong's blog</title><link>https://liangweidonggood.github.io/categories/%E7%BC%96%E7%A8%8B/</link><description>Recent content in 编程 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/categories/%E7%BC%96%E7%A8%8B/index.xml" rel="self" type="application/rss+xml"/><item><title>AQS原理简述</title><link>https://liangweidonggood.github.io/p/13-aqs-yuan-li-jian-shu/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/13-aqs-yuan-li-jian-shu/</guid><description>&lt;h2 id="225-aqs原理简述"&gt;§2.2.5 AQS原理简述
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：理解AQS作为JUC基石的原理深度，而非泛泛而谈&amp;quot;抽象队列同步器&amp;quot;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;AQS（AbstractQueuedSynchronizer）是JUC锁和同步器（ReentrantLock、CountDownLatch、Semaphore等）的基石。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心三要素&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;volatile int state&lt;/code&gt;——同步状态（独占模式0表示未锁，大于0表示已锁；共享模式表示剩余资源数）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CLH变体双向队列&lt;/strong&gt;——等待获取锁的线程队列，每个节点通过CAS和前驱节点的waitStatus状态协作&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模板方法模式&lt;/strong&gt;——子类实现tryAcquire/tryRelease等抽象方法决定同步语义，AQS内部维护队列和状态流转&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;独占模式获取锁流程&lt;/strong&gt;：tryAcquire尝试获取 → 成功则返回 → 失败则将当前线程包装成Node加入等待队列 → 在队列中自旋或阻塞等待前驱节点唤醒。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;项目层面&lt;/strong&gt;：日常使用多是读API层面（直接用ReentrantLock、CountDownLatch），没有深入到定制AQS同步器那个层面。但对AQS的CLH队列原理、state状态机有清晰理解。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：说&amp;quot;精通AQS&amp;quot;结果说不出CLH队列原理；泛泛而谈&amp;quot;抽象队列同步器&amp;quot;没深度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;备选话术&lt;/strong&gt;：我日常使用线程池处理异步任务（如设备数据批量写入），对JUC核心类有实操经验。但AQS源码实现细节或无锁编程（CAS/Unsafe）不是日常写代码的层面，坦诚需要查资料。&lt;/p&gt;</description></item><item><title>JDK LTS版本新特性（8 / 11 / 17 / 21）</title><link>https://liangweidonggood.github.io/p/08-jdk-lts-xin-te-xing/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/08-jdk-lts-xin-te-xing/</guid><description>&lt;h2 id="218-jdk-lts版本新特性8--11--17--21"&gt;§2.1.8 JDK LTS版本新特性（8 / 11 / 17 / 21）
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：是否跟得上Java生态演进，知道每个LTS版本的关键变化和升级价值。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;Oracle 2017年宣布6个月发布周期（3月/9月），每2年一个LTS（长期支持版本）。截至目前四个主要LTS：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;JDK 8（2014.03）——革命性版本，目前仍有海量存量&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;strong&gt;Lambda + Stream API&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;函数式编程，集合操作的声明式写法&lt;/td&gt;
					&lt;td&gt;Java 8的核心卖点，改变了Java编程范式&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Optional类&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;优雅处理null，避免NPE&lt;/td&gt;
					&lt;td&gt;链式调用，配合orElse/orElseGet兜底&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;新的日期时间API&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;java.time包（LocalDate/LocalDateTime/Instant）&lt;/td&gt;
					&lt;td&gt;线程安全+不可变对象，替代joda-time&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;code&gt;default&lt;/code&gt;关键字，接口可提供默认实现&lt;/td&gt;
					&lt;td&gt;不破坏实现类的情况下给接口加新方法&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Metaspace替代PermGen&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;方法区移到本地内存&lt;/td&gt;
					&lt;td&gt;不再OOM: PermGen space&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;CompletableFuture&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;异步编程组合能力&lt;/td&gt;
					&lt;td&gt;thenApply/thenCompose/thenCombine编排异步任务&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;JDK 11（2018.09 LTS）——模块化成熟、HTTP Client标准化&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;strong&gt;Java Platform Module System&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;从JDK 9开始的模块化（Project Jigsaw），JDK 11达稳定&lt;/td&gt;
					&lt;td&gt;拆大单体应用、控制可访问性、&lt;code&gt;module-info.java&lt;/code&gt;声明依赖（团队小不一定需要）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;HttpClient标准化&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;java.net.http.HttpClient&lt;/code&gt;替代第三方库&lt;/td&gt;
					&lt;td&gt;原生支持HTTP/2、WebSocket、异步请求&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ZGC实验性&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;亚毫秒停顿GC&lt;/td&gt;
					&lt;td&gt;JDK 11首次引入（实验性），JDK 15生产可用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Epsilon GC&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;只分配内存不回收的&amp;quot;假GC&amp;quot;&lt;/td&gt;
					&lt;td&gt;性能基准测试、短生命周期应用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Flight Recorder开源&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;JFR性能分析工具（原商业版）&lt;/td&gt;
					&lt;td&gt;零性能损耗的生产环境Profiling&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;var局部变量推导&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;var list = new ArrayList&amp;lt;String&amp;gt;()&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;减少样板代码（从JDK 10开始）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;移除内容&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Java EE模块（JAXB/JAX-WS）被移除&lt;/td&gt;
					&lt;td&gt;迁移要注意：旧项目升级要额外加JAXB等依赖&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;收费政策&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Oracle JDK 11起商用收费&lt;/td&gt;
					&lt;td&gt;OpenJDK免费，以此版本为分界线&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;JDK 17（2021.09 LTS）——当前主流LTS，G1/GC全面成熟&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;strong&gt;Sealed Classes&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;sealed class Shape permits Circle, Rectangle&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;受控继承，编译期保证子类列表，增强类型安全&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Pattern Matching for switch&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;switch支持类型匹配和解构（预览）&lt;/td&gt;
					&lt;td&gt;减少instanceof+强转的模板代码&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Record类&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;record Point(int x, int y){}&lt;/code&gt; 一行搞定数据载体&lt;/td&gt;
					&lt;td&gt;消除getter/setter/equals/hashCode/toString（从JDK 14正式）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Text Blocks&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;quot;&amp;quot;&amp;quot;...&amp;quot;&amp;quot;&amp;quot;&lt;/code&gt; 多行文本块&lt;/td&gt;
					&lt;td&gt;SQL/JSON/HTML不再用string拼接（从JDK 15正式）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;增强型伪随机数生成器&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;新接口+新算法（LXM系列）&lt;/td&gt;
					&lt;td&gt;高性能多线程随机数生成&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Foreign Function &amp;amp; Memory API&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;替代JNI的现代方案（孵化）&lt;/td&gt;
					&lt;td&gt;安全高效调用C/C++代码&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;macOS AArch64支持&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;原生支持Apple M1/M2芯片&lt;/td&gt;
					&lt;td&gt;无需Rosetta转译&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;G1成为事实标准&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;多年打磨，大堆场景表现稳定&lt;/td&gt;
					&lt;td&gt;多数项目升级JDK 17的直接理由&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;JDK 21（2023.09 LTS）——最新LTS，虚拟线程时代来临&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;strong&gt;Virtual Threads（虚拟线程）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Project Loom正式落地&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;JDK 21最大卖点&lt;/strong&gt;——数百万轻量级线程，阻塞操作几乎免费。Spring Boot 3.2已集成&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Pattern Matching for switch（正式）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;switch模式匹配结束预览，正式GA&lt;/td&gt;
					&lt;td&gt;类型安全+解构式编程&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Record Patterns&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;嵌套解构Record对象&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;if (p instanceof Point(int x, int y) &amp;amp;&amp;amp; x &amp;gt; 0)&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Sequenced Collections&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;有序集合统一接口 &lt;code&gt;getFirst()/getLast()/addFirst()/addLast()&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;List/Deque/SortedSet有统一的操作有序元素的API&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;String Templates（预览）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;STR.&amp;quot;Hello \{name}&amp;quot;&lt;/code&gt; 字符串模板&lt;/td&gt;
					&lt;td&gt;替代String.format和字符串拼接&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Scoped Values（预览）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;线程间共享不可变数据的新方案&lt;/td&gt;
					&lt;td&gt;替代ThreadLocal部分场景（轻量、明确生命周期）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Structured Concurrency（预览）&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;结构化并发，&lt;code&gt;StructuredTaskScope&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;把多个并发子任务作为一个&amp;quot;工作单元&amp;quot;管理&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ZGC正式支持分代&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;ZGC从单代发展为分代回收&lt;/td&gt;
					&lt;td&gt;进一步提升吞吐量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Key Encapsulation Mechanism API&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;抗量子加密（PQC）支持&lt;/td&gt;
					&lt;td&gt;面向未来的安全&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;LTS升级路径建议&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;/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;JDK 8 ──→ JDK 11（稳妥保守派，最小迁移成本）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ──→ JDK 17（推荐跳板，G1成熟+Record+密封类）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ──→ JDK 21（激进尝鲜派，虚拟线程巨大诱惑）
&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;p&gt;目前主力在JDK 8上，原因是客户本地部署环境限制——很多客户只有JDK 8的授权或安全基线认证。升级到JDK 11/17的最大阻力不是技术（代码兼容性很好），而是客户的环境审批流程。但如果是新项目或云端部署，我会直接选JDK 17——Record+Sealed Classes提升代码表达力、G1比JDK 8的Parallel更稳定、长期支持到2029年。如果场景有高并发连接需求（比如Netty做数万设备同时接入），那我就选JDK 21——虚拟线程让一个TCP连接一个虚拟线程成为可能，代码模型从异步回调退化为同步写法但性能不降。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：把var说成&amp;quot;和JS一样动态类型&amp;quot;（var是编译期类型推断，运行时强类型）；不知道JDK 11 Oracle JDK开始商用收费；不知道ZGC不同版本的状态（实验性/生产可用/分代）；把Record和Lombok @Data简单等同（Record是不可变对象，Lombok是可变）；不知道虚拟线程和平台线程的本质区别（虚拟线程由JVM调度，不绑定OS线程）。&lt;/p&gt;</description></item><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>synchronized vs Lock</title><link>https://liangweidonggood.github.io/p/09-synchronized-yu-lock/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/09-synchronized-yu-lock/</guid><description>&lt;h2 id="221-synchronized-vs-lock"&gt;§2.2.1 synchronized vs Lock
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：能否理解synchronized和Lock的原理差异和选型依据。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;synchronized是JVM内置锁，由monitorenter/monitorexit字节码指令实现，自动释放锁，非公平锁，适合简单同步场景。&lt;/p&gt;
&lt;p&gt;Lock（ReentrantLock）是JDK API级别的锁，通过AQS（AbstractQueuedSynchronizer）实现，必须手动释放（finally中unlock），支持公平锁、可中断获取锁、尝试获取锁超时、多条件变量（Condition），适合复杂同步场景。&lt;/p&gt;
&lt;p&gt;JDK 6以后synchronized做了锁升级优化——偏向锁 → 轻量级锁 → 重量级锁，单线程竞争场景下性能差距不大。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;追问预判&lt;/strong&gt;：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;追问：&amp;ldquo;synchronized的锁升级过程具体是怎样的？&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;无锁状态 → 偏向锁：Mark Word存储线程ID，同一线程重入不走CAS，直接判断线程ID一致 → 轻量级锁：多个线程交替竞争时，自旋CAS尝试获取锁，Mark Word存锁记录指针 → 重量级锁：自旋超过阈值（默认10次或自适应），升级为OS互斥量，线程阻塞挂起。本质是空间换时间——偏向锁和轻量级锁尽力减少内核态切换，重量级锁是兜底方案。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：说不清锁升级过程；以为synchronized一直是重量级锁。&lt;/p&gt;</description></item><item><title>ThreadLocal原理与内存泄漏</title><link>https://liangweidonggood.github.io/p/11-threadlocal-yu-nei-cun-xie-lou/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/11-threadlocal-yu-nei-cun-xie-lou/</guid><description>&lt;h2 id="223-threadlocal原理与内存泄漏"&gt;§2.2.3 ThreadLocal原理与内存泄漏
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：是否理解ThreadLocal的实现原理、内存泄漏成因及规避方式。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;每个Thread内部维护一个ThreadLocalMap，key是ThreadLocal实例的弱引用（WeakReference），value是线程持有的值。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;内存泄漏原因&lt;/strong&gt;：在线程池场景下线程复用，ThreadLocal使用完没有调用remove()时——key（ThreadLocal实例）会被GC回收（弱引用特点），但value的强引用链依然存在（Thread → ThreadLocalMap → Entry → value），导致value无法被回收，造成内存泄漏。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;规范&lt;/strong&gt;：ThreadLocal使用完必须在finally块中调用remove()。&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;/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;ThreadLocal&amp;lt;Object&amp;gt; tl = new ThreadLocal&amp;lt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;try {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tl.set(value);
&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;} finally {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tl.remove();
&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;p&gt;&lt;strong&gt;追问预判&lt;/strong&gt;：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;追问：&amp;ldquo;为什么ThreadLocalMap的key要设计成弱引用？&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;设计为弱引用的目的是：当ThreadLocal对象不再被外部强引用时（即使用方不再需要它了），GC可以回收ThreadLocal实例，使得对应的Entry（key=null）成为无效条目。下次ThreadLocalMap调用set/get/remove时会主动清理这些key为null的Entry。如果没有这一层弱引用设计，即使外部不再使用ThreadLocal，Entry和value也会一直存活，导致更严重的内存泄漏。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：答不出弱引用设计意图；只知道&amp;quot;用ThreadLocal存用户信息&amp;quot;但说不清泄漏原理。&lt;/p&gt;</description></item><item><title>volatile深入</title><link>https://liangweidonggood.github.io/p/10-volatile-shen-ru/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/10-volatile-shen-ru/</guid><description>&lt;h2 id="222-volatile深入"&gt;§2.2.2 volatile深入
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：volatile是面试高频基础题。初级答&amp;quot;保证可见性+禁止重排序&amp;quot;，中极答内存屏障语义，高级能讲出实际项目中用它解决过什么并发bug。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;一、volatile的两个核心作用&lt;/strong&gt;（基础层，必须熟练）&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;保证可见性&lt;/strong&gt;：一个线程修改volatile变量后，其他线程立即可见。底层通过lock前缀指令触发缓存一致性协议（MESI），写变量时强制将缓存行写回主存并使其他CPU核的缓存行失效，其他核读时必须从主存重新加载。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;禁止指令重排序&lt;/strong&gt;：通过内存屏障限制编译器和CPU的指令重排。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;不保证原子性&lt;/strong&gt;：&lt;code&gt;volatile int i; i++&lt;/code&gt;不是原子操作（读→改→写三步），多线程并发自增仍然会丢失更新。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;二、内存屏障详解&lt;/strong&gt;（深度层，拉开分差）&lt;/p&gt;
&lt;p&gt;内存屏障是一条CPU指令，强制在其前后的内存操作满足特定的执行顺序。Java的volatile通过JMM定义的四类屏障保证了Happens-Before语义：&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;strong&gt;LoadLoad&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Load1; LoadLoad; Load2&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;保证Load1在Load2之前完成（防止读操作重排到前面的读之前）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;StoreStore&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Store1; StoreStore; Store2&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;保证Store1在Store2之前完成（防止写操作重排到前面的写之前）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;LoadStore&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Load1; LoadStore; Store2&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;保证Load1在Store2之前完成（防止写操作重排到前面的读之前）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;StoreLoad&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Store1; StoreLoad; Load2&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;保证Store1在Load2之前完成（防止读操作重排到前面的写之前）&lt;strong&gt;最重的一类屏障，同时具备其他三种效果，通常由 &lt;code&gt;mfence&lt;/code&gt;或 &lt;code&gt;lock addl&lt;/code&gt;指令实现&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;volatile的内存屏障插入策略&lt;/strong&gt;（JMM规范）：&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-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// volatile 写之前
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;StoreStore屏障 ← 保证volatile写之前的普通写操作对volatile写可见
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// volatile 写
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;StoreLoad屏障 ← 保证volatile写之后的读操作不会被重排到volatile写之前
&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;// volatile 读
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LoadLoad屏障 ← 保证volatile读之后的普通读不会被重排到volatile读之前
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// volatile 读
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LoadStore屏障 ← 保证volatile读之后的普通写不会被重排到volatile读之前
&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;为什么StoreLoad屏障最重？&lt;/strong&gt; 它要求在执行StoreLoad之后的任何Load指令前，Store缓冲区中的所有数据必须全部刷新到主存（或者至少对其他处理器可见）。在x86平台上，&lt;code&gt;StoreLoad&lt;/code&gt;通常由 &lt;code&gt;mfence&lt;/code&gt;（全屏障）或带lock前缀的指令实现，开销是普通指令的几十到上百倍。而LoadLoad、StoreStore、LoadStore在x86上通常无需额外指令——x86本身就是强内存模型（TSO），只允许Store-Load重排，其他重排在硬件层面已被禁止。所以在x86上，volatile的实际开销主要来自StoreLoad屏障。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;三、volatile实用场景&lt;/strong&gt;（实战层，证明你真正用过）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;场景1：DCL（双重检查锁定）单例中的volatile&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;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeviceConfigManager&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DeviceConfigManager&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DeviceConfigManager&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ①第一次判空&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DeviceConfigManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ②第二次判空&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DeviceConfigManager&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ③危险操作&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&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;code&gt;instance&lt;/code&gt;必须用volatile？&lt;/strong&gt; 关键在第③行 &lt;code&gt;new DeviceConfigManager()&lt;/code&gt;，这行代码在JVM层面分三步：&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;/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;1. memory = allocate() // 分配内存空间
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2. ctorInstance(memory) // 初始化对象（执行构造方法）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3. instance = memory // 将引用指向分配的内存地址
&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;如果不用volatile，步骤2和3可能被重排成1→3→2。线程A执行 &lt;code&gt;new&lt;/code&gt;指令时刚好走到&amp;quot;分配内存→赋值引用&amp;quot;但构造方法还没执行完（对象是半成品），线程B走到第①行 &lt;code&gt;if (instance == null)&lt;/code&gt;发现instance非空，直接返回了一个&lt;strong&gt;没有初始化完成的对象&lt;/strong&gt;——后续使用时NullPointerException或数据错乱。volatile的StoreStore屏障保证了步骤2一定在步骤3之前完成（写前插入StoreStore：&lt;code&gt;ctorInstance; StoreStore; instance=memory&lt;/code&gt;），线程B读instance时LoadLoad屏障保证读到的对象一定是初始化完毕的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;场景2：线程安全的状态标志位&lt;/strong&gt;（实战项目）：&lt;/p&gt;
&lt;p&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;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&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-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PositionEngine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 不用volatile——reload线程改了flag，worker线程可能永远看不到&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// private boolean configChanged = true;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 用volatile——reload线程一改，所有worker线程下次循环立即感知&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;boolean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;configChanged&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PositionConfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 注意：config本身不是volatile&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 定时任务线程每5分钟刷新一次&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;reloadConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PositionConfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newConfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loadFromRemote&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ①先加载完整新配置&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ②再赋值给config&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;configChanged&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ③最后改标记&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// volatile写前的StoreStore屏障保证①②③不会重排——&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 所以configChanged变为false时，config一定是新值&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 几十个工作线程每秒调用数千次&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;calcPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Device&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configChanged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// volatile读后的LoadLoad屏障保证——&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 读到configChanged=true时，config一定已经是最新赋值&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;updateLocalConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;configChanged&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ... 定位计算，用本地缓存的config，不走volatile，零开销&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&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;这个场景volatile的妙处&lt;/strong&gt;：配置变量 &lt;code&gt;config&lt;/code&gt;本身&lt;strong&gt;不需要&lt;/strong&gt;volatile修饰。volatile只用于 &lt;code&gt;configChanged&lt;/code&gt;这个&amp;quot;开关变量&amp;quot;，利用volatile写前StoreStore屏障保证&amp;quot;先赋值config、再改标记&amp;quot;的写入顺序，利用volatile读后LoadLoad屏障保证&amp;quot;先读标记确认、再读config内容&amp;quot;的读取顺序。这种&amp;quot;volatile变量守卫普通变量&amp;quot;的模式比把所有变量都标volatile高效得多。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;场景3：安全发布（Safe Publication）&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;在物联平台设备接入时，每个设备连接对应的Handler需要持有设备基础信息。这个信息在主线程初始化，被NIO的Worker线程读取：&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;span class="lnt"&gt;21
&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-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeviceHandler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DeviceInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deviceInfo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 必须volatile&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 主线程启动时调用一次&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deviceId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DeviceInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DeviceInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deviceId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ①构造完整对象&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProtocol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;modbus&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ②设置所有属性&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLocation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;井下一区&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deviceInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ③发布——volatile写&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// StoreStore屏障：保证①②所有初始化在③赋值之前被所有线程可见&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Netty Worker线程读取&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;onData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DeviceInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deviceInfo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// LoadLoad屏障：读到的info对象一定是完整初始化的&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProtocol&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 必然返回&amp;#34;modbus&amp;#34;，不会是null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&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;如果没有volatile，Worker线程可能看到 &lt;code&gt;deviceInfo&lt;/code&gt;非空（引用已赋值），但 &lt;code&gt;info&lt;/code&gt;对象的内部属性还是初始值（构造函数未完整执行被重排），导致 &lt;code&gt;getProtocol()&lt;/code&gt;返回null而NPE。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：说&amp;quot;volatile能保证原子性&amp;quot;——致命错误（i++反例）；说&amp;quot;所有共享变量都需要volatile&amp;quot;——过于暴力，性能代价大；知道四种屏障名字但说不出各自阻止什么重排；不知道DCL单例为什么必须volatile（JDK 5之前volatile语义不够强，DCL有bug）；不知道x86只需要StoreLoad屏障（LoadLoad/StoreStore/StoreLoad在x86上硬件已保证，伪共享除外）。&lt;/p&gt;</description></item><item><title>各JDK版本垃圾回收器</title><link>https://liangweidonggood.github.io/p/03-ge-jdk-ban-ben-la-ji-hui-shou-qi/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/03-ge-jdk-ban-ben-la-ji-hui-shou-qi/</guid><description>&lt;h2 id="213-各jdk版本垃圾回收器"&gt;§2.1.3 各JDK版本垃圾回收器
&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;JDK发展史就是&amp;quot;降低GC停顿时间&amp;quot;的演进史——从秒级到毫秒级到亚毫秒级：&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;停顿特点&lt;/th&gt;
					&lt;th&gt;适用场景&lt;/th&gt;
					&lt;th&gt;JDK版本&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Serial&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;新生代&lt;/td&gt;
					&lt;td&gt;标记-复制&lt;/td&gt;
					&lt;td&gt;单线程STW，几十~几百ms&lt;/td&gt;
					&lt;td&gt;单核、Client模式、几百MB堆&lt;/td&gt;
					&lt;td&gt;1.3+&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Serial Old&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;老年代&lt;/td&gt;
					&lt;td&gt;标记-整理&lt;/td&gt;
					&lt;td&gt;单线程STW&lt;/td&gt;
					&lt;td&gt;配合Serial&lt;/td&gt;
					&lt;td&gt;1.3+&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Parallel Scavenge&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;新生代&lt;/td&gt;
					&lt;td&gt;标记-复制&lt;/td&gt;
					&lt;td&gt;多线程STW，吞吐量优先&lt;/td&gt;
					&lt;td&gt;批处理、科学计算&lt;/td&gt;
					&lt;td&gt;1.4+&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Parallel Old&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;老年代&lt;/td&gt;
					&lt;td&gt;标记-整理&lt;/td&gt;
					&lt;td&gt;多线程STW&lt;/td&gt;
					&lt;td&gt;配合Parallel Scavenge&lt;/td&gt;
					&lt;td&gt;1.6+&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;CMS&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;老年代&lt;/td&gt;
					&lt;td&gt;标记-清除&lt;/td&gt;
					&lt;td&gt;并发低停顿，最耗时的并发标记和并发清除阶段与用户线程并发&lt;/td&gt;
					&lt;td&gt;互联网Web应用（响应时间优先）&lt;/td&gt;
					&lt;td&gt;1.5-14&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;G1&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;整堆&lt;/td&gt;
					&lt;td&gt;标记-整理+复制&lt;/td&gt;
					&lt;td&gt;可预测停顿，Region化&lt;/td&gt;
					&lt;td&gt;JDK 9默认、大堆(&amp;gt;4G)、对停顿有要求的服务端&lt;/td&gt;
					&lt;td&gt;7u4+&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ZGC&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;整堆&lt;/td&gt;
					&lt;td&gt;染色指针+并发整理&lt;/td&gt;
					&lt;td&gt;亚毫秒级停顿(&amp;lt;1ms)&lt;/td&gt;
					&lt;td&gt;超大堆(&amp;gt;16G)、极致低延迟&lt;/td&gt;
					&lt;td&gt;11+(实验) / 15+(生产)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Shenandoah&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;整堆&lt;/td&gt;
					&lt;td&gt;并发复制+Brooks转发指针&lt;/td&gt;
					&lt;td&gt;低停顿&lt;/td&gt;
					&lt;td&gt;超大堆低延迟&lt;/td&gt;
					&lt;td&gt;12+(Red Hat主导)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;CMS（Concurrent Mark Sweep）——并发低停顿的先驱&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;四个阶段：①初始标记（STW，扫描GC Roots直接引用，极快）→ ②并发标记（与用户线程并发，从GC Roots遍历整个对象图，最耗时）→ ③重新标记（STW，处理并发标记期间变动的引用，修正标记结果）→ ④并发清除（与用户线程并发）。&lt;/p&gt;
&lt;p&gt;CMS的致命缺陷：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内存碎片&lt;/strong&gt;——标记-清除不整理，碎片严重时触发Serial Old全堆整理（单线程，停顿秒级）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;浮动垃圾&lt;/strong&gt;——并发标记和清除期间用户线程产生的垃圾，只能等下次GC处理。需预留老年代空间给这些浮动垃圾，否则触发&lt;strong&gt;Concurrent Mode Failure&lt;/strong&gt;，降级为Serial Old&lt;/li&gt;
&lt;li&gt;JDK 14已废弃，JDK 15移除&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;G1（Garbage First）——JDK 9+默认，划时代的分区回收器&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;核心创新——将堆划分为等大小的&lt;strong&gt;Region&lt;/strong&gt;（默认2048个，每个1~32MB），不再按物理分代。Region分为Eden、Survivor、Old、Humongous四种类型。&lt;/p&gt;
&lt;p&gt;G1的混合GC（Mixed GC）：不止回收新生代，还回收部分收益最高的老年代Region——&lt;strong&gt;每次回收&amp;quot;垃圾最多的Region&amp;quot;&lt;/strong&gt;，这也是Garbage First名字的来源。&lt;/p&gt;
&lt;p&gt;关键机制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SATB（Snapshot At The Beginning）&lt;/strong&gt;：并发标记开始时的对象图快照，保证标记正确性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RSet（Remembered Set）&lt;/strong&gt;：每个Region维护其他Region指向本Region的引用，避免全堆扫描&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可预测停顿&lt;/strong&gt;：&lt;code&gt;-XX:MaxGCPauseMillis&lt;/code&gt;设定目标（默认200ms），G1自动调整回收Region数量&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Humongous对象&lt;/strong&gt;：超过Region大小50%的对象放入Humongous Region。大量短命大对象会引发频繁GC——需要调整Region大小或优化应用代码&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;G1 vs CMS直观对比：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;G1无内存碎片（标记-复制+整理），CMS有碎片问题&lt;/li&gt;
&lt;li&gt;G1停顿可预测可控，CMS的不确定性大&lt;/li&gt;
&lt;li&gt;G1的吞吐量略低于CMS（RSet维护开销），但换来更稳定的延迟&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;ZGC（Z Garbage Collector）——亚毫秒级停顿的终极方案&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;核心创新——&lt;strong&gt;染色指针（Colored Pointer）&lt;/strong&gt;：在64位指针中嵌入GC状态信息（共4位：Finalizable/Remapped/Marked 1/Marked 0），标记阶段不修改对象头，只修改指针颜色。结合读屏障（Load Barrier）实现并发整理——应用线程读对象时发现指针颜色不对，触发地址修正，在访问过程中完成GC。&lt;/p&gt;
&lt;p&gt;关键特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;停顿时间不随堆大小增长——16MB堆&amp;lt;1ms，16TB堆也是&amp;lt;1ms&lt;/li&gt;
&lt;li&gt;支持TB级堆、毫秒级回收、JDK 15生产可用&lt;/li&gt;
&lt;li&gt;限制：仅Linux x64；吞吐量比G1低约5-10%（读屏障开销）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;JDK版本与默认回收器对照速查&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;JDK版本&lt;/th&gt;
					&lt;th&gt;默认回收器&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;JDK 8&lt;/td&gt;
					&lt;td&gt;Parallel Scavenge + Parallel Old（吞吐量优先）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;JDK 9-16&lt;/td&gt;
					&lt;td&gt;G1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;JDK 17+&lt;/td&gt;
					&lt;td&gt;G1（LTS）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;JDK 21&lt;/td&gt;
					&lt;td&gt;G1（新一代ZGC也在成熟，但G1仍是默认）&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;面试官可能会问&amp;quot;你们项目用的什么回收器，为什么？&amp;quot;&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;项目部署在JDK 8上，默认Parallel Scavenge+Parallel Old。但我们实际指定了G1——原因：①堆内存配了4-8G，G1对这个区间的优化最好；②安全生产平台是面向客户的服务端应用，客户对接口响应时间敏感，G1的可预测停顿比Parallel的吞吐量优先更适合；③大量设备数据写入导致新生代对象产生速度快，Parallel的STW时间随堆增长接近1秒，G1的停顿控制在200ms以内。上了G1后加上 &lt;code&gt;-XX:MaxGCPauseMillis=100&lt;/code&gt;调优，P99延迟从800ms降到了300ms。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：把G1说成简单的&amp;quot;分Region的CMS&amp;quot;；不知道CMS在JDK 14已废弃；不知道JDK 8默认是Parallel而非G1；说不出ZGC的核心创新（染色指针）；GC选型说不出业务场景理由。&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><item><title>线程池核心参数与执行流程</title><link>https://liangweidonggood.github.io/p/12-xian-cheng-chi-he-xin-can-shu/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/12-xian-cheng-chi-he-xin-can-shu/</guid><description>&lt;h2 id="224-线程池核心参数与执行流程"&gt;§2.2.4 线程池核心参数与执行流程
&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;七个核心参数&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;corePoolSize&lt;/code&gt;——常驻线程数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maximumPoolSize&lt;/code&gt;——最大线程数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keepAliveTime&lt;/code&gt;——空闲线程存活时间（超过corePoolSize的线程）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TimeUnit&lt;/code&gt;——时间单位&lt;/li&gt;
&lt;li&gt;&lt;code&gt;workQueue&lt;/code&gt;——阻塞队列（有界/无界）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;threadFactory&lt;/code&gt;——线程工厂（自定义线程名、是否守护线程等）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;handler&lt;/code&gt;——拒绝策略&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;执行流程&lt;/strong&gt;：
提交任务 → 当前线程数 &amp;lt; corePoolSize → 创建核心线程执行
→ 当前线程数 &amp;gt;= corePoolSize → 入队列等待
→ 队列满 → 创建非核心线程执行
→ 当前线程数 &amp;gt;= maximumPoolSize → 触发拒绝策略&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;AbortPolicy（默认）&lt;/td&gt;
					&lt;td&gt;抛RejectedExecutionException&lt;/td&gt;
					&lt;td&gt;必须感知任务丢失的场景&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CallerRunsPolicy&lt;/td&gt;
					&lt;td&gt;调用者线程执行&lt;/td&gt;
					&lt;td&gt;反向压制动，降低任务提交速度&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;DiscardPolicy&lt;/td&gt;
					&lt;td&gt;直接丢弃，静默失败&lt;/td&gt;
					&lt;td&gt;不重要的日志/统计任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;DiscardOldestPolicy&lt;/td&gt;
					&lt;td&gt;丢弃队列最老的未处理任务&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;：在物联平台用线程池处理设备数据批量写入。I/O密集型任务核心线程数设为CPU核数×2，队列用有界ArrayBlockingQueue防止内存溢出。自定义ThreadFactory设置线程名前缀方便排查。拒绝策略用CallerRunsPolicy做背压。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：背参数但说不清业务场景下怎么选型和调参。&lt;/p&gt;</description></item><item><title>ArrayList vs LinkedList</title><link>https://liangweidonggood.github.io/p/16-arraylist-yu-linkedlist/</link><pubDate>Thu, 06 Mar 2008 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/16-arraylist-yu-linkedlist/</guid><description>&lt;h2 id="233-arraylist-vs-linkedlist"&gt;§2.3.3 ArrayList vs LinkedList
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：是否理解List不同实现的性能差异及工程选型判断。&lt;/p&gt;

 &lt;/blockquote&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;ArrayList&lt;/th&gt;
					&lt;th&gt;LinkedList&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;底层结构&lt;/td&gt;
					&lt;td&gt;动态数组（Object[]）&lt;/td&gt;
					&lt;td&gt;双向链表（Node）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;随机访问&lt;/td&gt;
					&lt;td&gt;O(1)&lt;/td&gt;
					&lt;td&gt;O(n)——需要遍历&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;尾部插入&lt;/td&gt;
					&lt;td&gt;O(1)均摊（扩容时O(n)）&lt;/td&gt;
					&lt;td&gt;O(1)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;头/中间插入&lt;/td&gt;
					&lt;td&gt;O(n)（需要移动元素）&lt;/td&gt;
					&lt;td&gt;头O(1)，中间O(n)——定位+O(1)插入&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;内存开销&lt;/td&gt;
					&lt;td&gt;连续内存，数据紧凑&lt;/td&gt;
					&lt;td&gt;每个节点额外存储prev+next指针&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;工程实践&lt;/strong&gt;：实际开发中ArrayList用得更多。原因是内存连续、CPU缓存友好（缓存行预读），大多数场景下遍历性能远超LinkedList。LinkedList的优势场景是频繁头尾插入删除（如队列、栈）。日常开发90%场景ArrayList够用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ArrayList扩容&lt;/strong&gt;：默认初始容量10，扩容时增长为原来的1.5倍（&lt;code&gt;oldCapacity + (oldCapacity &amp;gt;&amp;gt; 1)&lt;/code&gt;），通过&lt;code&gt;Arrays.copyOf&lt;/code&gt;拷贝数组。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：不知道ArrayList扩容机制细节；说&amp;quot;LinkedList插入快&amp;quot;不考虑定位开销。&lt;/p&gt;</description></item><item><title>HashMap原理</title><link>https://liangweidonggood.github.io/p/14-hashmap-yuan-li/</link><pubDate>Tue, 06 Jun 2006 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/14-hashmap-yuan-li/</guid><description>&lt;h2 id="231-hashmap原理"&gt;§2.3.1 HashMap原理
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：是否理解HashMap的数据结构演进、put流程、扩容与树化等关键机制。&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;：JDK 7：数组+链表。JDK 8：数组+链表/红黑树。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;put流程&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;计算key的hash值（高16位异或低16位，降低hash冲突）&lt;/li&gt;
&lt;li&gt;定位桶：&lt;code&gt;(n - 1) &amp;amp; hash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;无冲突 → 直接放入&lt;/li&gt;
&lt;li&gt;有冲突 → 判断equals → 相同则覆盖，不同则尾插（JDK 7是头插，JDK 8改尾插避免死链）&lt;/li&gt;
&lt;li&gt;链表长度 &amp;gt; 8 且数组长度 ≥ 64 → 树化为红黑树&lt;/li&gt;
&lt;li&gt;容量超过 threshold（capacity × loadFactor）→ 扩容&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;扩容机制&lt;/strong&gt;：2倍扩容，JDK 8做了rehash优化——原hash值与oldCap按位与，结果为0留在原位，为1移到&amp;quot;原位置+oldCap&amp;quot;，省去了每次rebuild hash表的开销。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;负载因子0.75&lt;/strong&gt;：时间和空间的折中。太低（如0.5）浪费内存；太高（如1）hash冲突增加，影响查询性能。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;红黑树退化&lt;/strong&gt;：resize时如果树的节点数 ≤ 6，退化为链表。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：说&amp;quot;HashMap线程安全&amp;quot;；不知道树化阈值是链表长度&amp;gt;8且数组长度≥64两个条件缺一不可。&lt;/p&gt;</description></item><item><title>ConcurrentHashMap原理</title><link>https://liangweidonggood.github.io/p/15-concurrenthashmap-yuan-li/</link><pubDate>Thu, 06 Apr 2006 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/15-concurrenthashmap-yuan-li/</guid><description>&lt;h2 id="232-concurrenthashmap原理"&gt;§2.3.2 ConcurrentHashMap原理
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：是否理解ConcurrentHashMap在JDK 7/8的演进及JDK 8的改进要点。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;JDK 7（分段锁）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据结构：Segment数组 + HashEntry数组 + 链表&lt;/li&gt;
&lt;li&gt;Segment继承ReentrantLock，默认16个Segment&lt;/li&gt;
&lt;li&gt;理论上支持16个线程并发写（每个Segment一把锁）&lt;/li&gt;
&lt;li&gt;并发度固定不可动态调整&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;JDK 8（CAS + synchronized）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据结构：Node数组 + 链表/红黑树&lt;/li&gt;
&lt;li&gt;put时CAS尝试插入空桶，CAS失败则synchronized锁桶头节点再插入&lt;/li&gt;
&lt;li&gt;锁粒度从Segment级别（一锁锁一段）细化到桶级别（一锁锁一个桶），并发度更高&lt;/li&gt;
&lt;li&gt;扩容支持多线程并发——transferIndex分段迁移，每个线程负责一段区域的rehash&lt;/li&gt;
&lt;li&gt;JDK 8改synchronized而非ReentrantLock的原因：JDK 6后synchronized性能足够；省去Segment对象的内存开销；锁粒度更细带来的收益远超锁机制本身的微小差异&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：仍停留在JDK 7分段锁的理解；不知道JDK 8为什么改CAS+synchronized。&lt;/p&gt;</description></item></channel></rss>