Files
www/public/blogs/java/jvm/JVM-类加载.html
zhuhjay 22e48d9558 build(www): 添加 Drone CI 流水线配置
- 新增 .drone.yml 文件用于定义 CI/CD 流程
- 配置了基于 Docker 的部署步骤
- 设置了工作区和卷映射以支持持久化数据
- 添加了构建准备阶段和 Docker 部署阶段
- 定义了环境变量和代理设置
- 配置了 artifacts 目录的处理逻辑
- 添加了 timezone 映射以确保时间同步
- 设置了 docker.sock 映射以支持 Docker in Docker
2025-11-01 13:36:00 +08:00

650 lines
172 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>JVM之类加载 | ZhuHJay Blog</title>
<meta name="generator" content="VuePress 1.9.7">
<link rel="icon" href="/favicon.ico">
<meta name="description" content="my blog">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<link rel="preload" href="/assets/css/0.styles.93f9cd2e.css" as="style"><link rel="preload" href="/assets/js/app.049e1b5b.js" as="script"><link rel="preload" href="/assets/js/3.ff0e945d.js" as="script"><link rel="preload" href="/assets/js/1.1ced4111.js" as="script"><link rel="preload" href="/assets/js/21.2956f057.js" as="script"><link rel="prefetch" href="/assets/js/10.21e2f029.js"><link rel="prefetch" href="/assets/js/11.18770288.js"><link rel="prefetch" href="/assets/js/12.588a1dd8.js"><link rel="prefetch" href="/assets/js/13.e66c15d0.js"><link rel="prefetch" href="/assets/js/14.141a3334.js"><link rel="prefetch" href="/assets/js/15.bd05cf61.js"><link rel="prefetch" href="/assets/js/16.346083d6.js"><link rel="prefetch" href="/assets/js/17.382f52f1.js"><link rel="prefetch" href="/assets/js/18.a55369bc.js"><link rel="prefetch" href="/assets/js/19.a2a264ee.js"><link rel="prefetch" href="/assets/js/20.c6871f96.js"><link rel="prefetch" href="/assets/js/4.581595e5.js"><link rel="prefetch" href="/assets/js/5.55d6cfd7.js"><link rel="prefetch" href="/assets/js/6.9619dc5e.js"><link rel="prefetch" href="/assets/js/7.d2b7a379.js"><link rel="prefetch" href="/assets/js/8.9f502ca9.js"><link rel="prefetch" href="/assets/js/9.ec0bd674.js">
<link rel="stylesheet" href="/assets/css/0.styles.93f9cd2e.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container" data-v-7dd95ae2><div data-v-7dd95ae2><div class="password-shadow password-wrapper-out" style="display:none;" data-v-59e6cb88 data-v-7dd95ae2 data-v-7dd95ae2><h3 class="title" data-v-59e6cb88>ZhuHJay Blog</h3> <p class="description" data-v-59e6cb88>my blog</p> <label id="box" class="inputBox" data-v-59e6cb88><input type="password" value="" data-v-59e6cb88> <span data-v-59e6cb88>Konck! Knock!</span> <button data-v-59e6cb88>OK</button></label> <div class="footer" data-v-59e6cb88><span data-v-59e6cb88><i class="iconfont reco-theme" data-v-59e6cb88></i> <a target="blank" href="https://vuepress-theme-reco.recoluan.com" data-v-59e6cb88>vuePress-theme-reco</a></span> <span data-v-59e6cb88><i class="iconfont reco-copyright" data-v-59e6cb88></i> <a data-v-59e6cb88><span data-v-59e6cb88>ZhuHJay</span>
  
<span data-v-59e6cb88>2021 - </span>
2025
</a></span></div></div> <div class="hide" data-v-7dd95ae2><header class="navbar" data-v-7dd95ae2><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="/logo.png" alt="ZhuHJay Blog" class="logo"> <span class="site-name">ZhuHJay Blog</span></a> <div class="links"><div class="color-picker"><a class="color-button"><i class="iconfont reco-color"></i></a> <div class="color-picker-menu" style="display:none;"><div class="mode-options"><h4 class="title">Choose mode</h4> <ul class="color-mode-options"><li class="dark">dark</li><li class="auto active">auto</li><li class="light">light</li></ul></div></div></div> <div class="search-box"><i class="iconfont reco-search"></i> <input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/" class="nav-link"><i class="iconfont reco-home"></i>
首页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="iconfont reco-category"></i>
分类
</span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/categories/Java/" class="nav-link"><i class="undefined"></i>
Java
</a></li><li class="dropdown-item"><!----> <a href="/categories/NoSQL/" class="nav-link"><i class="undefined"></i>
NoSQL
</a></li><li class="dropdown-item"><!----> <a href="/categories/JavaScript/" class="nav-link"><i class="undefined"></i>
JavaScript
</a></li></ul></div></div><div class="nav-item"><a href="/tag/" class="nav-link"><i class="iconfont reco-tag"></i>
标签
</a></div><div class="nav-item"><a href="https://gitee.com/ZhuHJay" target="_blank" rel="noopener noreferrer" class="nav-link external"><i class="iconfont reco-mayun"></i>
码云
<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div> <!----></nav></div></header> <div class="sidebar-mask" data-v-7dd95ae2></div> <aside class="sidebar" data-v-7dd95ae2><div class="personal-info-wrapper" data-v-1fad0c41 data-v-7dd95ae2><img src="/avatar.png" alt="author-avatar" class="personal-img" data-v-1fad0c41> <h3 class="name" data-v-1fad0c41>
ZhuHJay
</h3> <div class="num" data-v-1fad0c41><div data-v-1fad0c41><h3 data-v-1fad0c41>11</h3> <h6 data-v-1fad0c41>文章</h6></div> <div data-v-1fad0c41><h3 data-v-1fad0c41>5</h3> <h6 data-v-1fad0c41>标签</h6></div></div> <ul class="social-links" data-v-1fad0c41></ul> <hr data-v-1fad0c41></div> <nav class="nav-links"><div class="nav-item"><a href="/" class="nav-link"><i class="iconfont reco-home"></i>
首页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="iconfont reco-category"></i>
分类
</span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/categories/Java/" class="nav-link"><i class="undefined"></i>
Java
</a></li><li class="dropdown-item"><!----> <a href="/categories/NoSQL/" class="nav-link"><i class="undefined"></i>
NoSQL
</a></li><li class="dropdown-item"><!----> <a href="/categories/JavaScript/" class="nav-link"><i class="undefined"></i>
JavaScript
</a></li></ul></div></div><div class="nav-item"><a href="/tag/" class="nav-link"><i class="iconfont reco-tag"></i>
标签
</a></div><div class="nav-item"><a href="https://gitee.com/ZhuHJay" target="_blank" rel="noopener noreferrer" class="nav-link external"><i class="iconfont reco-mayun"></i>
码云
<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div> <!----></nav> <ul class="sidebar-links"><li><a href="/blogs/java/jvm/JVM-内存结构.html" class="sidebar-link">JVM之内存结构</a></li><li><a href="/blogs/java/jvm/JVM-垃圾回收.html" class="sidebar-link">JVM之垃圾回收</a></li><li><a href="/blogs/java/jvm/JVM-字节码技术.html" class="sidebar-link">JVM之字节码技术</a></li><li><a href="/blogs/java/jvm/JVM-类加载.html" class="active sidebar-link">JVM之类加载</a></li></ul> </aside> <div class="password-shadow password-wrapper-in" style="display:none;" data-v-59e6cb88 data-v-7dd95ae2><h3 class="title" data-v-59e6cb88>JVM之类加载</h3> <!----> <label id="box" class="inputBox" data-v-59e6cb88><input type="password" value="" data-v-59e6cb88> <span data-v-59e6cb88>Konck! Knock!</span> <button data-v-59e6cb88>OK</button></label> <div class="footer" data-v-59e6cb88><span data-v-59e6cb88><i class="iconfont reco-theme" data-v-59e6cb88></i> <a target="blank" href="https://vuepress-theme-reco.recoluan.com" data-v-59e6cb88>vuePress-theme-reco</a></span> <span data-v-59e6cb88><i class="iconfont reco-copyright" data-v-59e6cb88></i> <a data-v-59e6cb88><span data-v-59e6cb88>ZhuHJay</span>
  
<span data-v-59e6cb88>2021 - </span>
2025
</a></span></div></div> <div data-v-7dd95ae2><div data-v-7dd95ae2><main class="page"><section style="display:;"><div class="page-title"><h1 class="title">JVM之类加载</h1> <div data-v-8a445198><i class="iconfont reco-account" data-v-8a445198><span data-v-8a445198>ZhuHJay</span></i> <i class="iconfont reco-date" data-v-8a445198><span data-v-8a445198>2022/12/9</span></i> <!----> <i class="tags iconfont reco-tag" data-v-8a445198><span class="tag-item" data-v-8a445198>JVM</span></i></div></div> <div class="theme-reco-content content__default"><h2 id="_1-类加载阶段"><a href="#_1-类加载阶段" class="header-anchor">#</a> 1 类加载阶段</h2> <h3 id="_1-1-加载"><a href="#_1-1-加载" class="header-anchor">#</a> 1.1 加载</h3> <ul><li><p>将类的字节码载入方法区中,内部采用 C++ 的 <code>instanceKlass</code> 描述 java 类,它的重要 <code>field</code> 有:</p> <ul><li><p><code>_java_mirror</code> 即 java 的类镜像,例如对 String 来说,就是 String.class作用是把 klass 暴露给 java 使用,是一个桥梁</p></li> <li><p><code>_super</code> 即父类</p></li> <li><p><code>_fields</code> 即成员变量</p></li> <li><p><code>_methods</code> 即方法</p></li> <li><p><code>_constants</code> 即常量池</p></li> <li><p><code>_class_loader</code> 即类加载器</p></li> <li><p><code>_vtable</code> 虚方法表</p></li> <li><p><code>_itable</code> 接口方法表</p></li></ul></li> <li><p>如果这个类还有父类没有加载,先加载父类</p></li> <li><p>加载和链接可能是交替运行的</p></li></ul> <blockquote><p><strong>注意</strong></p> <ul><li><code>instanceKlass</code> 这样的【元数据】是存储在方法区1.8 后的元空间内),但 <code>_java_mirror</code> 是存储在堆中</li> <li>可以通过前面介绍的 <code>HSDB</code> 工具查看</li></ul></blockquote> <p><img src="/jvm/1670419734596.png" alt="1670419734596"></p> <h3 id="_1-2-链接"><a href="#_1-2-链接" class="header-anchor">#</a> 1.2 链接</h3> <h4 id="_1-验证"><a href="#_1-验证" class="header-anchor">#</a> 1) 验证</h4> <p>验证类是否符合 JVM规范安全性检查</p> <p>修改 <code>HelloWorld.class</code> 的魔数,在控制台运行</p> <ul><li><code>Incompatible magic value</code>JVM 检查到了不兼容的魔数</li></ul> <div class="language-shell line-numbers-mode"><pre class="language-shell"><code>G:<span class="token punctuation">\</span>Idea_workspace<span class="token punctuation">\</span>JVM<span class="token punctuation">\</span>src<span class="token punctuation">\</span>main<span class="token punctuation">\</span>java<span class="token operator">&gt;</span>java HelloWorld
Error: A JNI error has occurred, please check your installation and try again
Exception <span class="token keyword">in</span> thread <span class="token string">&quot;main&quot;</span> java.lang.ClassFormatError: Incompatible magic value <span class="token number">1514689864</span> <span class="token keyword">in</span> class <span class="token function">file</span> HelloWorld
at java.lang.ClassLoader.defineClass1<span class="token punctuation">(</span>Native Method<span class="token punctuation">)</span>
at java.lang.ClassLoader.defineClass<span class="token punctuation">(</span>ClassLoader.java:756<span class="token punctuation">)</span>
at java.security.SecureClassLoader.defineClass<span class="token punctuation">(</span>SecureClassLoader.java:142<span class="token punctuation">)</span>
at java.net.URLClassLoader.defineClass<span class="token punctuation">(</span>URLClassLoader.java:473<span class="token punctuation">)</span>
at java.net.URLClassLoader.access<span class="token variable">$100</span><span class="token punctuation">(</span>URLClassLoader.java:74<span class="token punctuation">)</span>
at java.net.URLClassLoader<span class="token variable">$1</span>.run<span class="token punctuation">(</span>URLClassLoader.java:369<span class="token punctuation">)</span>
at java.net.URLClassLoader<span class="token variable">$1</span>.run<span class="token punctuation">(</span>URLClassLoader.java:363<span class="token punctuation">)</span>
at java.security.AccessController.doPrivileged<span class="token punctuation">(</span>Native Method<span class="token punctuation">)</span>
at java.net.URLClassLoader.findClass<span class="token punctuation">(</span>URLClassLoader.java:362<span class="token punctuation">)</span>
at java.lang.ClassLoader.loadClass<span class="token punctuation">(</span>ClassLoader.java:418<span class="token punctuation">)</span>
at sun.misc.Launcher<span class="token variable">$AppClassLoader</span>.loadClass<span class="token punctuation">(</span>Launcher.java:355<span class="token punctuation">)</span>
at java.lang.ClassLoader.loadClass<span class="token punctuation">(</span>ClassLoader.java:351<span class="token punctuation">)</span>
at sun.launcher.LauncherHelper.checkAndLoadMain<span class="token punctuation">(</span>LauncherHelper.java:601<span class="token punctuation">)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br></div></div><h4 id="_2-准备"><a href="#_2-准备" class="header-anchor">#</a> 2) 准备</h4> <p>为 static 变量分配空间,设置默认值</p> <ul><li>static 变量在 <code>JDK 7</code> 之前存储于 <code>instanceKlass</code> 末尾,从<code>JDK 7</code> 开始,存储于 <code>_java_mirror</code>末尾</li> <li>static 变量<em>分配空间和赋值是两个步骤</em>,分配空间在准备阶段完成,赋值在初始化阶段完成</li> <li>如果 static 变量是 <code>final</code><em>基本类型,以及字符串常量</em>,那么编译阶段值就确定了,赋值在<strong>准备阶段</strong>完成</li> <li>如果 static 变量是 <code>final</code> 的,但属于<em>引用类型</em>,那么赋值也会在<strong>初始化阶段</strong>完成</li></ul> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Load1</span> <span class="token punctuation">{</span>
<span class="token keyword">static</span> <span class="token keyword">int</span> a<span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token keyword">int</span> b <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> c <span class="token operator">=</span> <span class="token number">30</span><span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> d <span class="token operator">=</span> <span class="token string">&quot;qwe&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> e <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token string">&quot;asd&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>以上代码的字节码为,印证以下结果</p> <ul><li>static 关键字声明的常量在 <strong>编译阶段完成</strong> 空间分配,在 <strong>初始化阶段</strong> 完成赋值</li> <li>static + final 关键字声明的常量且是 <em>基本类型或字符串常量</em>,在 <strong>编译阶段</strong> 就有了确定的值,且在 <strong>准备阶段</strong> 完成赋值</li> <li>static + final 关键字声明的常量且是 <em>引用类型</em>,需要在 <strong>初始化阶段</strong> 完成赋值</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>static int a;
descriptor: I
flags: ACC_STATIC
static int b;
descriptor: I
flags: ACC_STATIC
static final int c;
descriptor: I
flags: ACC_STATIC, ACC_FINAL
ConstantValue: int 30
static final java.lang.String d;
descriptor: Ljava/lang/String;
flags: ACC_STATIC, ACC_FINAL
ConstantValue: String qwe
static final java.lang.String e;
descriptor: Ljava/lang/String;
flags: ACC_STATIC, ACC_FINAL
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=3, locals=0, args_size=0
0: bipush 20
2: putstatic #2 // 20 -&gt; b
5: new #3 // class java/lang/String
8: dup
9: ldc #4 // &lt;- &quot;asd&quot;
11: invokespecial #5 // Method java/lang/String.&quot;&lt;init&gt;&quot;:(Ljava/lang/String;)V
14: putstatic #6 // &quot;asd&quot; -&gt; e
17: return
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br></div></div><h4 id="_3-解析"><a href="#_3-解析" class="header-anchor">#</a> 3) 解析</h4> <p>将常量池中的符号引用解析为直接引用</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>zhuhjay<span class="token punctuation">.</span>demo4</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Load2</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
<span class="token class-name">ClassLoader</span> classLoader <span class="token operator">=</span> <span class="token class-name">Load2</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 使用 loadClass 方法加载的类不会触发类的解析和初始化</span>
<span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> aClass <span class="token operator">=</span> classLoader<span class="token punctuation">.</span><span class="token function">loadClass</span><span class="token punctuation">(</span><span class="token string">&quot;com.zhuhjay.demo4.C&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>in<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">class</span> <span class="token class-name">C</span> <span class="token punctuation">{</span>
<span class="token class-name">D</span> d <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">D</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">class</span> <span class="token class-name">D</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><p>接下来打开 <code>HSDB</code> 工具(在 JDK 目录下执行命令) <code>java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB</code></p> <p>查看是否存在类 D以及类 C 中的常量池信息</p> <ul><li>以上代码执行后只会存在类C对象而类D对象只存在字节码信息不会进行解析</li></ul> <p><img src="/jvm/1670427087000.png" alt="1670427087000"></p> <p>而如果直接创建了对象那么就会存在类C和类D对象此时类C和类D将会被解析完</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>zhuhjay<span class="token punctuation">.</span>demo4</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Load2</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
<span class="token class-name">ClassLoader</span> classLoader <span class="token operator">=</span> <span class="token class-name">Load2</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 使用 loadClass 方法加载的类不会触发类的解析和初始化</span>
<span class="token comment">// Class&lt;?&gt; aClass = classLoader.loadClass(&quot;com.zhuhjay.demo4.C&quot;);</span>
<span class="token keyword">new</span> <span class="token class-name">C</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>in<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><h3 id="_1-3-初始化"><a href="#_1-3-初始化" class="header-anchor">#</a> 1.3 初始化</h3> <h4 id="clinit-v"><a href="#clinit-v" class="header-anchor">#</a> <code>&lt;clinit&gt;()V</code></h4> <p>初始化即调用 <code>&lt;clinit&gt;()V</code> ,虚拟机会保证这个类的『构造方法』的线程安全</p> <h4 id="发生时机"><a href="#发生时机" class="header-anchor">#</a> 发生时机</h4> <p>概括得说,类初始化是【懒惰的】</p> <ul><li>main 方法所在的类,总会被首先初始化</li> <li>首次访问这个类的静态变量或静态方法时</li> <li>子类初始化,如果父类还没初始化,会引发</li> <li>子类访问父类的静态变量,只会触发父类的初始化</li> <li>Class.forName</li> <li>new 会导致初始化</li></ul> <p>不会导致类初始化的情况</p> <ul><li>访问类的 static final 静态常量(基本类型和字符串)不会触发初始化</li> <li>类.class 不会触发初始化</li> <li>创建该类的数组不会触发初始化</li> <li>类加载器的 loadClass 方法</li> <li>Class.forName 的参数 2 为 false</li></ul> <p>使用以下代码对以上进行验证(依次执行)</p> <ol start="0"><li>当只有一个空的 mian 方法进行执行时,会有 <code>main init</code> main 方法所在的类,总会被首先初始化</li> <li><code>final static double b = 5.0</code> 不会导致初始化过程产生:访问类的 static final 静态常量(基本类型和字符串)不会触发初始化</li> <li><code>B.class</code> 不会触发初始化</li> <li><code>new B[0]</code> 不会触发初始化</li> <li><code>c1.loadClass(&quot;com.zhuhjay.demo4.B&quot;)</code> 会加载类B以及父类A但不会触发初始化</li> <li><code>Class.forName(&quot;com.zhuhjay.demo4.B&quot;, false, c2)</code> 会加载类B以及父类A但不会触发初始化</li> <li><code>static int a = 0</code> 在初始化阶段才进行赋值,此时会触发初始化</li> <li><code>static boolean c = false</code> 在初始化阶段进行赋值,子类初始化触发会引发父类初始化</li> <li>使用子类访问父类 <code>static int a = 0</code>,只会触发父类的初始化</li> <li><code>Class.forName(&quot;com.zhuhjay.demo4.B&quot;)</code> 会触发初始化,并且父类先进行初始化</li></ol> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>zhuhjay<span class="token punctuation">.</span>demo4</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Load3</span> <span class="token punctuation">{</span>
<span class="token keyword">static</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;main init&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
<span class="token comment">// 1. 静态常量不会触发初始化</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">B</span><span class="token punctuation">.</span>b<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 2. 类.class 不会触发初始化</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">B</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 3. 创建类的数组不会触发初始化</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">B</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 4. 不会初始化类B但会加载 B、A</span>
<span class="token class-name">ClassLoader</span> c1 <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getContextClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
c1<span class="token punctuation">.</span><span class="token function">loadClass</span><span class="token punctuation">(</span><span class="token string">&quot;com.zhuhjay.demo4.B&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 5. 不会初始化类B 但会加载 B、A</span>
<span class="token class-name">ClassLoader</span> c2 <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getContextClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Class</span><span class="token punctuation">.</span><span class="token function">forName</span><span class="token punctuation">(</span><span class="token string">&quot;com.zhuhjay.demo4.B&quot;</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">,</span> c2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 6. 首次访问这个类的静态变量或静态方法时</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">A</span><span class="token punctuation">.</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 7. 子类初始化,如果父类还没初始化,会引发</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">B</span><span class="token punctuation">.</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 8. 子类访问父类的静态变量,只会触发父类的初始化</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">B</span><span class="token punctuation">.</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 9. 会初始化类B并先初始化类A</span>
<span class="token class-name">Class</span><span class="token punctuation">.</span><span class="token function">forName</span><span class="token punctuation">(</span><span class="token string">&quot;com.zhuhjay.demo4.B&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token punctuation">{</span>
<span class="token keyword">static</span> <span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;a init&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">class</span> <span class="token class-name">B</span> <span class="token keyword">extends</span> <span class="token class-name">A</span> <span class="token punctuation">{</span>
<span class="token keyword">final</span> <span class="token keyword">static</span> <span class="token keyword">double</span> b <span class="token operator">=</span> <span class="token number">5.0</span><span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token keyword">boolean</span> c <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;b init&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br></div></div><h3 id="_1-4-练习"><a href="#_1-4-练习" class="header-anchor">#</a> 1.4 练习</h3> <p>判断以下代码哪些会触发E的初始化</p> <ul><li><code>public static final Integer c = 20</code> 在编译阶段会转换为 <code>public static final Integer c = Integer.valueOf(20)</code>访问变量c会触发初始化方法</li></ul> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Load4</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">E</span><span class="token punctuation">.</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">E</span><span class="token punctuation">.</span>b<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">E</span><span class="token punctuation">.</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">class</span> <span class="token class-name">E</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> b <span class="token operator">=</span> <span class="token string">&quot;qwe&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Integer</span> c <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;E init&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><p>懒惰初始化单例模式</p> <ul><li>懒惰的、线程安全的</li> <li>只有在调用 <code>getInstance()</code> 方法的时候, 静态内部类 <code>LazyHolder</code> 才会被初始化</li></ul> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Load5</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
<span class="token class-name">Singleton</span><span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">class</span> <span class="token class-name">Singleton</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">LazyHolder</span> <span class="token punctuation">{</span>
<span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Singleton</span> <span class="token constant">INSTANCE</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;LazyHolder init&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Singleton</span> <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token class-name">LazyHolder</span><span class="token punctuation">.</span><span class="token constant">INSTANCE</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;test method&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br></div></div><h2 id="_2-类加载器"><a href="#_2-类加载器" class="header-anchor">#</a> 2 类加载器</h2> <p>以 JDK 8 为例:</p> <table><thead><tr><th>名称</th> <th>加载哪的类</th> <th>说明</th></tr></thead> <tbody><tr><td>Bootstrap ClassLoader</td> <td>JAVA_HOME/jre/lib</td> <td>无法直接访问</td></tr> <tr><td>Extension ClassLoader</td> <td>JAVA_HOME/jre/lib/ext</td> <td>上级为 Bootstrap显示为 null</td></tr> <tr><td>Application ClassLoader</td> <td>classpath</td> <td>上级为 Extension</td></tr> <tr><td>自定义类加载器</td> <td>自定义</td> <td>上级为 Application</td></tr></tbody></table> <p>在加载一个类时,首先会向上级的类加载器&quot;询问&quot;是否可以进行类的加载,如果上级加载器可以加载,则由上级加载器加载,否则由 Application ClassLoader 进行类的加载。这就是<strong>双亲委派机制</strong></p> <ul><li>由于 Bootstrap ClassLoader 是由 C++ 运行的,所以该类加载器无法直接访问,以 null 存在</li></ul> <h3 id="_2-1-启动类加载器"><a href="#_2-1-启动类加载器" class="header-anchor">#</a> 2.1 启动类加载器</h3> <p>用 Bootstrap 类加载器加载类:</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>zhuhjay<span class="token punctuation">.</span>demo4</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Load6</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
<span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> aClass <span class="token operator">=</span> <span class="token class-name">Class</span><span class="token punctuation">.</span><span class="token function">forName</span><span class="token punctuation">(</span><span class="token string">&quot;com.zhuhjay.demo4.F&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>aClass<span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">class</span> <span class="token class-name">F</span> <span class="token punctuation">{</span>
<span class="token keyword">static</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;Bootstrap F init&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p>将上述代码编译执行一次过后打开对应的class文件输出目录执行命令 <code>java -Xbootclasspath/a:. com.zhuhjay.demo4.Load6</code> 会出现以下输出结果,<code>aClass.getClassLoader()</code> 结果为 <code>null</code> 即为 Bootstrap 类加载器</p> <ul><li><code>-Xbootclasspath</code> 表示设置 <code>bootclasspath</code></li> <li>其中 <code>/a:.</code> 表示将当前目录追加至 <code>bootclasspath</code> 之后</li> <li>可以用这个办法替换核心类(修改 Bootstrap 类加载器 加载的目录)
<ul><li><code>java -Xbootclasspath:&lt;new bootclasspath&gt;</code></li> <li><code>java -Xbootclasspath/a:&lt;追加路径&gt;</code>:后追加</li> <li><code>java -Xbootclasspath/p:&lt;追加路径&gt;</code>:前追加</li></ul></li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>Bootstrap F init
null
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h3 id="_2-2-扩展类加载器"><a href="#_2-2-扩展类加载器" class="header-anchor">#</a> 2.2 扩展类加载器</h3> <p>编译执行以下代码</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">G</span> <span class="token punctuation">{</span>
<span class="token keyword">static</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;ext classpath G init&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Load7</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
<span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> aClass <span class="token operator">=</span> <span class="token class-name">Class</span><span class="token punctuation">.</span><span class="token function">forName</span><span class="token punctuation">(</span><span class="token string">&quot;com.zhuhjay.demo4.G&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>aClass<span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>移步至 class 输出目录下,使用命令 <code>jar -cvf my.jar com/zhuhjay/demo4/G.class</code> 对类G生成jar包将生成后的jar包复制到 JDK 目录下的 <code>jre/lib/ext</code> 中,然后将 G 改为以下</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">G</span> <span class="token punctuation">{</span>
<span class="token keyword">static</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;classpath G init&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>再次执行 Load7 得到结果</p> <ul><li>执行的类G是在 JDK 目录下的,并且由 Extension ClassLoader 进行该类的创建使得自己写的类G失效印证了双亲委派启动&gt;扩展&gt;应用&gt;自定义)</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>ext classpath G init
sun.misc.Launcher$ExtClassLoader@7f31245a
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h3 id="_2-3-双亲委派模式"><a href="#_2-3-双亲委派模式" class="header-anchor">#</a> 2.3 双亲委派模式</h3> <p>所谓的双亲委派,就是指调用类加载器的 <code>loadClass</code> 方法时,查找类的规则</p> <ul><li>双亲委派并没有<strong>继承关系</strong>,而是一种委托</li></ul> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> <span class="token function">loadClass</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">,</span> <span class="token keyword">boolean</span> resolve<span class="token punctuation">)</span>
<span class="token keyword">throws</span> <span class="token class-name">ClassNotFoundException</span>
<span class="token punctuation">{</span>
<span class="token keyword">synchronized</span> <span class="token punctuation">(</span><span class="token function">getClassLoadingLock</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// First, check if the class has already been loaded</span>
<span class="token comment">// 1. 检查该类是否已经加载</span>
<span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> c <span class="token operator">=</span> <span class="token function">findLoadedClass</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>c <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">long</span> t0 <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">nanoTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>parent <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 2. 如果存在上级加载器,那么将委托执行 loadClass</span>
c <span class="token operator">=</span> parent<span class="token punctuation">.</span><span class="token function">loadClass</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token comment">// 3. 如果没有上级ExtClassLoader则委派 BootstrapClassLoader</span>
c <span class="token operator">=</span> <span class="token function">findBootstrapClassOrNull</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">ClassNotFoundException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// ClassNotFoundException thrown if class not found</span>
<span class="token comment">// from the non-null parent class loader</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>c <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// If still not found, then invoke findClass in order</span>
<span class="token comment">// to find the class.</span>
<span class="token keyword">long</span> t1 <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">nanoTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 4. 都找不到,那么就调用 findClass每个类加载器自己扩展来加载</span>
c <span class="token operator">=</span> <span class="token function">findClass</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// this is the defining class loader; record the stats</span>
<span class="token comment">// 5. 记录耗时</span>
<span class="token class-name"><span class="token namespace">sun<span class="token punctuation">.</span>misc<span class="token punctuation">.</span></span>PerfCounter</span><span class="token punctuation">.</span><span class="token function">getParentDelegationTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addTime</span><span class="token punctuation">(</span>t1 <span class="token operator">-</span> t0<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token namespace">sun<span class="token punctuation">.</span>misc<span class="token punctuation">.</span></span>PerfCounter</span><span class="token punctuation">.</span><span class="token function">getFindClassTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addElapsedTimeFrom</span><span class="token punctuation">(</span>t1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name"><span class="token namespace">sun<span class="token punctuation">.</span>misc<span class="token punctuation">.</span></span>PerfCounter</span><span class="token punctuation">.</span><span class="token function">getFindClasses</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">increment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>resolve<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">resolveClass</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> c<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br></div></div><h3 id="_2-4-线程上下文类加载器"><a href="#_2-4-线程上下文类加载器" class="header-anchor">#</a> 2.4 线程上下文类加载器</h3> <p>我们在使用 JDBC 的时候,都需要加载 Driver 驱动,发现不写 <code>Class.forName(&quot;com.mysql.jdbc.Driver&quot;);</code> 也能正确加载该驱动并进行使用需要引入驱动jar</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 注册驱动</span>
<span class="token comment">// Class.forName(&quot;com.mysql.jdbc.Driver&quot;);</span>
<span class="token comment">// 使用 DriverManager 获取连接</span>
<span class="token class-name">Connection</span> connection <span class="token operator">=</span> <span class="token class-name">DriverManager</span><span class="token punctuation">.</span><span class="token function">getConnection</span><span class="token punctuation">(</span><span class="token string">&quot;jdbc:mysql:///test?useSSL=false&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;root&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;root&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Statement</span> statement <span class="token operator">=</span> connection<span class="token punctuation">.</span><span class="token function">createStatement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">ResultSet</span> resultSet <span class="token operator">=</span> statement<span class="token punctuation">.</span><span class="token function">executeQuery</span><span class="token punctuation">(</span><span class="token string">&quot;select * from user&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
resultSet<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>resultSet<span class="token punctuation">.</span><span class="token function">getString</span><span class="token punctuation">(</span><span class="token string">&quot;username&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>看看 DriverManager 源码,可以发现它好像自动去加载了驱动。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DriverManager</span> <span class="token punctuation">{</span>
<span class="token comment">// 注册驱动的集合</span>
<span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token keyword">static</span> <span class="token class-name">CopyOnWriteArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">DriverInfo</span><span class="token punctuation">&gt;</span></span> registeredDrivers <span class="token operator">=</span>
<span class="token keyword">new</span> <span class="token class-name">CopyOnWriteArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token punctuation">{</span>
<span class="token comment">// 初始化驱动</span>
<span class="token function">loadInitialDrivers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;JDBC DriverManager initialized&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>先获取看看 DriverManager 的类加载器,可以发现打印结果为 null证明说 DriverManager 是通过 Bootstrap ClassLoader 进行加载的,会到 <code>JAVA_HOME/jre/lib</code> 目录下进行类的搜索,但是显然 mysql驱动 文件并不是出现在 <code>JAVA_HOME/jre/lib</code> 目录下面,那为什么它却可以加载到 <code>com.mysql.jdbc.Driver</code></p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">DriverManager</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>看看源码中 <code>loadInitialDrivers()</code> 方法如何进行工作的</p> <ul><li><code>Class.forName(aDriver, true, ClassLoader.getSystemClassLoader());</code> 打破双亲委派机制,直接使用应用类加载器来进行驱动的类加载</li></ul> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">loadInitialDrivers</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">String</span> drivers<span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
drivers <span class="token operator">=</span> <span class="token class-name">AccessController</span><span class="token punctuation">.</span><span class="token function">doPrivileged</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">PrivilegedAction</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">getProperty</span><span class="token punctuation">(</span><span class="token string">&quot;jdbc.drivers&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
drivers <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 1) 使用 ServiceLoader 机制加载驱动,即 SPI</span>
<span class="token class-name">AccessController</span><span class="token punctuation">.</span><span class="token function">doPrivileged</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">PrivilegedAction</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Void</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">Void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">ServiceLoader</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Driver</span><span class="token punctuation">&gt;</span></span> loadedDrivers <span class="token operator">=</span> <span class="token class-name">ServiceLoader</span><span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span><span class="token class-name">Driver</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Iterator</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Driver</span><span class="token punctuation">&gt;</span></span> driversIterator <span class="token operator">=</span> loadedDrivers<span class="token punctuation">.</span><span class="token function">iterator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">try</span><span class="token punctuation">{</span>
<span class="token keyword">while</span><span class="token punctuation">(</span>driversIterator<span class="token punctuation">.</span><span class="token function">hasNext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
driversIterator<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span><span class="token punctuation">(</span><span class="token class-name">Throwable</span> t<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Do nothing</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;DriverManager.initialize: jdbc.drivers = &quot;</span> <span class="token operator">+</span> drivers<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 2) 使用 jdbc.drivers 定义的驱动名加载驱动</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>drivers <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> drivers<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span><span class="token string">&quot;&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> driversList <span class="token operator">=</span> drivers<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">&quot;:&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;number of Drivers:&quot;</span> <span class="token operator">+</span> driversList<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> aDriver <span class="token operator">:</span> driversList<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;DriverManager.Initialize: loading &quot;</span> <span class="token operator">+</span> aDriver<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 这里的 ClassLoader.getSystemClassLoader() 就是应用程序加载器</span>
<span class="token class-name">Class</span><span class="token punctuation">.</span><span class="token function">forName</span><span class="token punctuation">(</span>aDriver<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
<span class="token class-name">ClassLoader</span><span class="token punctuation">.</span><span class="token function">getSystemClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;DriverManager.Initialize: load failed: &quot;</span> <span class="token operator">+</span> ex<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br></div></div><p><code>1)</code> 中使用的就是大名鼎鼎的 <code>Service Provider Interface (SPI)</code></p> <ul><li><p>约定如下,在 jar 包的 <code>META-INF/services</code> 包下,以接口全限定名名为文件,文件内容是实现类名称(就像 <code>SpringBoot</code> 中使用的 <code>spring.factories</code> 文件)</p> <img src="/jvm/1670493540488.png" alt="1670493540488" style="zoom:50%;"></li></ul> <p>之后就可以使用以下 ServiceLoader 加载器来加载信息</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">ServiceLoader</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Driver</span><span class="token punctuation">&gt;</span></span> loadedDrivers <span class="token operator">=</span> <span class="token class-name">ServiceLoader</span><span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span><span class="token class-name">Driver</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Iterator</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Driver</span><span class="token punctuation">&gt;</span></span> driversIterator <span class="token operator">=</span> loadedDrivers<span class="token punctuation">.</span><span class="token function">iterator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">while</span><span class="token punctuation">(</span>driversIterator<span class="token punctuation">.</span><span class="token function">hasNext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
driversIterator<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>体现的是【面向接口编程+解耦】的思想,在下面一些框架中都运用了此思想:</p> <ul><li>JDBC</li> <li>Servlet 初始化器</li> <li>Spring 容器</li> <li>Dubbo对 SPI 进行了扩展)</li></ul> <p>接着看看 <code>ServiceLoader.load(Driver.class)</code> 方法</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">S</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">ServiceLoader</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">S</span><span class="token punctuation">&gt;</span></span> <span class="token function">load</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">S</span><span class="token punctuation">&gt;</span></span> service<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 获取线程上下文类加载器</span>
<span class="token class-name">ClassLoader</span> cl <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getContextClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token class-name">ServiceLoader</span><span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span>service<span class="token punctuation">,</span> cl<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>线程上下文类加载器是当前线程使用的类加载器,默认就是应用程序类加载器,它内部又是由 <code>Class.forName</code> 调用了线程上下文类加载器完成类加载,具体代码在 <code>ServiceLoader</code> 的内部类 <code>LazyIterator</code> 中:</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token class-name">S</span> <span class="token function">nextService</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">hasNextService</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">NoSuchElementException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">String</span> cn <span class="token operator">=</span> nextName<span class="token punctuation">;</span>
nextName <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> c <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
c <span class="token operator">=</span> <span class="token class-name">Class</span><span class="token punctuation">.</span><span class="token function">forName</span><span class="token punctuation">(</span>cn<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">,</span> loader<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">ClassNotFoundException</span> x<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">fail</span><span class="token punctuation">(</span>service<span class="token punctuation">,</span>
<span class="token string">&quot;Provider &quot;</span> <span class="token operator">+</span> cn <span class="token operator">+</span> <span class="token string">&quot; not found&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>service<span class="token punctuation">.</span><span class="token function">isAssignableFrom</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">fail</span><span class="token punctuation">(</span>service<span class="token punctuation">,</span>
<span class="token string">&quot;Provider &quot;</span> <span class="token operator">+</span> cn <span class="token operator">+</span> <span class="token string">&quot; not a subtype&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token class-name">S</span> p <span class="token operator">=</span> service<span class="token punctuation">.</span><span class="token function">cast</span><span class="token punctuation">(</span>c<span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
providers<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>cn<span class="token punctuation">,</span> p<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> p<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Throwable</span> x<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">fail</span><span class="token punctuation">(</span>service<span class="token punctuation">,</span>
<span class="token string">&quot;Provider &quot;</span> <span class="token operator">+</span> cn <span class="token operator">+</span> <span class="token string">&quot; could not be instantiated&quot;</span><span class="token punctuation">,</span>
x<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// This cannot happen</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br></div></div><h3 id="_2-5-自定义类加载器"><a href="#_2-5-自定义类加载器" class="header-anchor">#</a> 2.5 自定义类加载器</h3> <p>什么时候需要自定义类加载器</p> <ol><li>想加载非 classpath 随意路径中的类文件</li> <li>都是通过接口来使用实现,希望解耦时,常用在框架设计</li> <li>这些类希望予以隔离,不同应用的同名类都可以加载,不冲突,常见于 tomcat 容器</li></ol> <p>步骤:</p> <ol><li>继承 ClassLoader 父类</li> <li>要遵从双亲委派机制,重写 findClass 方法 注意不是重写 loadClass 方法,否则不会走双亲委派机制</li> <li>读取类文件的字节码</li> <li>调用父类的 defineClass 方法来加载类</li> <li>使用者调用该类加载器的 loadClass 方法</li></ol> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CustomClassLoader</span> <span class="token keyword">extends</span> <span class="token class-name">ClassLoader</span><span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">protected</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> <span class="token function">findClass</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ClassNotFoundException</span> <span class="token punctuation">{</span>
<span class="token comment">// 类加载路径</span>
<span class="token class-name">String</span> path <span class="token operator">=</span> <span class="token string">&quot;G:\\classpath\\&quot;</span> <span class="token operator">+</span> name <span class="token operator">+</span> <span class="token string">&quot;.class&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">(</span><span class="token class-name">ByteArrayOutputStream</span> os <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ByteArrayOutputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Files</span><span class="token punctuation">.</span><span class="token function">copy</span><span class="token punctuation">(</span><span class="token class-name">Paths</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">,</span> os<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 获取字节码数据的 byte 数组</span>
<span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> bytes <span class="token operator">=</span> os<span class="token punctuation">.</span><span class="token function">toByteArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 加载 Class 文件</span>
<span class="token keyword">return</span> <span class="token function">defineClass</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> bytes<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> bytes<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ClassNotFoundException</span><span class="token punctuation">(</span><span class="token string">&quot;类文件未找到&quot;</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><blockquote><p><strong>Tip</strong></p> <p> 判断两个类是否是同一个类:<strong>同样的包名、类名和使用相同的类加载器</strong></p></blockquote> <h2 id="_3-运行期优化"><a href="#_3-运行期优化" class="header-anchor">#</a> 3 运行期优化</h2> <h3 id="_3-1-即时编译"><a href="#_3-1-即时编译" class="header-anchor">#</a> 3.1 即时编译</h3> <h4 id="_1-分层编译"><a href="#_1-分层编译" class="header-anchor">#</a> 1) 分层编译</h4> <p>TieredCompilation</p> <p>现来执行以下代码</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">JIT1</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">200</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">long</span> start <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">nanoTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> <span class="token number">1000</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">new</span> <span class="token class-name">Object</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">long</span> end <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">nanoTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">&quot;%d\t%d\n&quot;</span><span class="token punctuation">,</span> i<span class="token punctuation">,</span> <span class="token punctuation">(</span>end <span class="token operator">-</span>start<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p>输出一下结果(进行了截断获取),发现</p> <ul><li>执行到差不多 69 次发现已经快了将近4倍</li> <li>执行到差不多 147 次发现已经快了将近100倍</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>0 30200
1 23800
...
67 18400
68 9100
...
145 9600
146 400
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>原因是什么呢?</p> <p>JVM 将执行状态分成了 5 个层次:</p> <ul><li>0 层解释执行Interpreter</li> <li>1 层,使用 C1 即时编译器编译执行(不带 profiling</li> <li>2 层,使用 C1 即时编译器编译执行(带基本的 profiling</li> <li>3 层,使用 C1 即时编译器编译执行(带完全的 profiling</li> <li>4 层,使用 C2 即时编译器编译执行</li></ul> <blockquote><p>profiling 是指在运行过程中收集一些程序执行状态的数据,例如【方法的调用次数】,【循环的 回边次数】等</p></blockquote> <p>即时编译器JIT与解释器的区别</p> <ul><li>解释器是将字节码解释为机器码,下次即使遇到相同的字节码,仍会执行重复的解释</li> <li>JIT 是将一些字节码编译为机器码,并存入 Code Cache下次遇到相同的代码直接执行无需再编译</li> <li>解释器是将字节码解释为针对所有平台都通用的机器码</li> <li>JIT 会根据平台类型,生成平台特定的机器码</li></ul> <p>对于占据大部分的不常用的代码,我们无需耗费时间将其编译成机器码,而是采取解释执行的方式运 行;另一方面,对于仅占据小部分的热点代码,我们则可以将其编译成机器码,以达到理想的运行速 度。 执行效率上简单比较一下 <code>Interpreter &lt; C1 &lt; C2</code>,总的目标是发现热点代码(<code>hotspot</code>名称的由来),优化之</p> <p>刚才的一种优化手段称之为【逃逸分析】,发现新建的对象是否逃逸。可以使用 <code>-XX:-DoEscapeAnalysis</code> 关闭逃逸分析,再运行刚才的示例观察结果</p> <p><a href="https://docs.oracle.com/en/java/javase/12/vm/java-hotspot-virtual-machine-performance-enhancements.html#GUID-D2E3DC58-D18B-4A6C-8167-4A1DFB4888E4" target="_blank" rel="noopener noreferrer">参考资料: Java HotSpot Virtual Machine Performance Enhancements (oracle.com)<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <h4 id="_2-方法内联"><a href="#_2-方法内联" class="header-anchor">#</a> 2) 方法内联</h4> <p>Inlining</p> <p>定义一个计算方法 square</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">square</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token keyword">int</span> i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> i <span class="token operator">*</span> i<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>将其调用</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token function">square</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token number">9</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>如果发现 square 是热点方法,并且长度不太长时,会进行内联,所谓的内联就是把方法内代码拷贝、 粘贴到调用者的位置:</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token number">9</span> <span class="token operator">*</span> <span class="token number">9</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>还能够进行常量折叠 (Constant Folding) 的优化</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token number">81</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>进行实验代码测试</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">JIT2</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">square</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token keyword">int</span> i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> i <span class="token operator">*</span> i<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> x <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">500</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">long</span> start <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">nanoTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> <span class="token number">1000</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
x <span class="token operator">=</span> <span class="token function">square</span><span class="token punctuation">(</span><span class="token number">9</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">long</span> end <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">nanoTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">&quot;%d\t%d\n&quot;</span><span class="token punctuation">,</span> i<span class="token punctuation">,</span> <span class="token punctuation">(</span>end <span class="token operator">-</span>start<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p>输出一下结果(进行了截断获取),发现</p> <ul><li>越后面的执行越快,已经被 JVM 优化了</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>0 1335400
1 38700
2 83100
...
64 9800
65 6400
...
252 0
253 0
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>接下来进行添加虚拟机参数来查看一些优化信息</p> <ul><li><p><code>-XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining</code>:打印方法内联的信息</p> <p>执行信息如下(只截取了一部分)</p> <ul><li>可以看见 square 方法被优化了三次,第三次甚至被标记为热点代码 <code>inline (hot)</code></li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>...
@ 28 com.zhuhjay.demo5.JIT2::square (4 bytes)
@ 38 java.lang.System::nanoTime (0 bytes) intrinsic
@ 11 java.lang.System::nanoTime (0 bytes) intrinsic
@ 28 com.zhuhjay.demo5.JIT2::square (4 bytes)
@ 38 java.lang.System::nanoTime (0 bytes) intrinsic
@ 28 com.zhuhjay.demo5.JIT2::square (4 bytes) inline (hot)
@ 38 java.lang.System::nanoTime (0 bytes) (intrinsic)
@ 11 java.lang.System::nanoTime (0 bytes) (intrinsic)
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div></li> <li><p><code>-XX:CompileCommand=dontinline,*JIT2.square</code>:禁止某个方法的方法内联,因为 Java 中也有很多使用了方法内联的,全部禁用会影响效率</p> <p>执行信息如下(只截取部分进行展示)</p> <ul><li>到了最后一次执行,也不能够优化为 0</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>CompilerOracle: dontinline *JIT2.square
0 106000
1 24000
...
65 6300
66 6600
...
498 5500
499 4800
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div></li> <li><p><code>-XX:+PrintCompilation</code>:打印编译信息</p></li></ul> <h4 id="_3-字段优化"><a href="#_3-字段优化" class="header-anchor">#</a> 3) 字段优化</h4> <p>JMH 基准测试请参考:<a href="http://openjdk.java.net/projects/code-tools/jmh/" target="_blank" rel="noopener noreferrer">http://openjdk.java.net/projects/code-tools/jmh/<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <p>为了保证配置的正确性,建议使用 archetype 生成 JMH 配置项目。cmd 运行下面这段代码:</p> <ul><li>解读:创建一个文件夹 jmh-test里面包含完整的 jmh 配置 pom 文件</li></ul> <div class="language-shell line-numbers-mode"><pre class="language-shell"><code>mvn archetype:generate ^
<span class="token parameter variable">-DinteractiveMode</span><span class="token operator">=</span>false ^
<span class="token parameter variable">-DarchetypeGroupId</span><span class="token operator">=</span>org.openjdk.jmh ^
<span class="token parameter variable">-DarchetypeArtifactId</span><span class="token operator">=</span>jmh-java-benchmark-archetype ^
<span class="token parameter variable">-DarchetypeVersion</span><span class="token operator">=</span><span class="token number">1.25</span> ^
<span class="token parameter variable">-DgroupId</span><span class="token operator">=</span>com.zhuhjay ^
<span class="token parameter variable">-DartifactId</span><span class="token operator">=</span>jmh-test ^
<span class="token parameter variable">-Dversion</span><span class="token operator">=</span><span class="token number">1.0</span>.0
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>将以上创建的项目导入到 IDEA并进行 Maven 加载,可能需要将 Maven 中的两个 jar 包使用 <a href="https://mvnrepository.com/" target="_blank" rel="noopener noreferrer">mvnrepository<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 进行下载手动使用maven 命令添加到仓库中,如果需要则使用以下命令进行安装</p> <div class="language-shell line-numbers-mode"><pre class="language-shell"><code>mvn install:install-file ^
<span class="token parameter variable">-Dfile</span><span class="token operator">=</span>/filepath/jmh-generator-annprocess-1.25.jar ^
<span class="token parameter variable">-DgroupId</span><span class="token operator">=</span>org.openjdk.jmh ^
<span class="token parameter variable">-DartifactId</span><span class="token operator">=</span>jmh-generator-annprocess ^
<span class="token parameter variable">-Dversion</span><span class="token operator">=</span><span class="token number">1.25</span> ^
<span class="token parameter variable">-Dpackaging</span><span class="token operator">=</span>jar
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><div class="language-shell line-numbers-mode"><pre class="language-shell"><code>mvn install:install-file ^
<span class="token parameter variable">-Dfile</span><span class="token operator">=</span>/filepath/jmh-core-1.25.jar ^
<span class="token parameter variable">-DgroupId</span><span class="token operator">=</span>org.openjdk.jmh ^
<span class="token parameter variable">-DartifactId</span><span class="token operator">=</span>jmh-core ^
<span class="token parameter variable">-Dversion</span><span class="token operator">=</span><span class="token number">1.25</span> ^
<span class="token parameter variable">-Dpackaging</span><span class="token operator">=</span>jar
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>可能还需要以下 maven 坐标</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.apache.commons<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>commons-math3<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>3.6.1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>以下为基准测试代码,三个测试方法都是对数字进行累加的操作</p> <ul><li><code>@Warmup(iterations = 2, time = 1)</code> <ul><li>进行几轮热身,让程序预热,使得对其进行充分的优化</li></ul></li> <li><code>@Measurement(iterations = 5, time = 1)</code> <ul><li>设置进行几轮测试,然后取平均值,较为直观</li></ul></li> <li><code>@Benchmark</code> 未来对该注解标识的方法进行测试</li> <li><code>@CompilerControl(CompilerControl.Mode.INLINE)</code> 控制被调用方法使用方法内联</li> <li>三个测试方法区别:
<ol><li>直接使用成员变量进行累加</li> <li>使用局部变量进行累加</li> <li>使用 foreach 对成员变量进行累加</li></ol></li></ul> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Warmup</span><span class="token punctuation">(</span>iterations <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">,</span> time <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Measurement</span><span class="token punctuation">(</span>iterations <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">,</span> time <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@State</span><span class="token punctuation">(</span><span class="token class-name">Scope<span class="token punctuation">.</span>Benchmark</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Benchmark1</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> elements <span class="token operator">=</span> <span class="token function">randomInts</span><span class="token punctuation">(</span><span class="token number">1_000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">randomInts</span><span class="token punctuation">(</span><span class="token keyword">int</span> size<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Random</span> random <span class="token operator">=</span> <span class="token class-name">ThreadLocalRandom</span><span class="token punctuation">.</span><span class="token function">current</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> values <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span>size<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> size<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
values<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> random<span class="token punctuation">.</span><span class="token function">nextInt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> values<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@Benchmark</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">test1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> elements<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">doSum</span><span class="token punctuation">(</span>elements<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@Benchmark</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">test2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> local <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>elements<span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> local<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">doSum</span><span class="token punctuation">(</span>local<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@Benchmark</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">test3</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> element <span class="token operator">:</span> elements<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">doSum</span><span class="token punctuation">(</span>element<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">static</span> <span class="token keyword">int</span> sum <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token annotation punctuation">@CompilerControl</span><span class="token punctuation">(</span><span class="token class-name">CompilerControl<span class="token punctuation">.</span>Mode</span><span class="token punctuation">.</span><span class="token constant">INLINE</span><span class="token punctuation">)</span>
<span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">doSum</span><span class="token punctuation">(</span><span class="token keyword">int</span> x<span class="token punctuation">)</span> <span class="token punctuation">{</span>
sum <span class="token operator">+=</span> x<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">RunnerException</span> <span class="token punctuation">{</span>
<span class="token class-name">Options</span> opt <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">OptionsBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">include</span><span class="token punctuation">(</span><span class="token class-name">Benchmark1</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">getSimpleName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">forks</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">new</span> <span class="token class-name">Runner</span><span class="token punctuation">(</span>opt<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br></div></div><p>首先启用 doSum 的方法内联,测试结果如下(每秒吞吐量,分数越高的更好)</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>Benchmark Mode Cnt Score Error Units
Benchmark1.test1 thrpt 5 3109424.624 ± 253596.436 ops/s
Benchmark1.test2 thrpt 5 3354988.133 ± 91779.242 ops/s
Benchmark1.test3 thrpt 5 3192089.287 ± 811172.283 ops/s
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>接下来禁用 doSum 方法内联</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@CompilerControl</span><span class="token punctuation">(</span><span class="token class-name">CompilerControl<span class="token punctuation">.</span>Mode</span><span class="token punctuation">.</span><span class="token constant">DONT_INLINE</span><span class="token punctuation">)</span>
<span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">doSum</span><span class="token punctuation">(</span><span class="token keyword">int</span> x<span class="token punctuation">)</span> <span class="token punctuation">{</span>
sum <span class="token operator">+=</span> x<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>此时测试结果如下跟以上结果对比发现吞吐量小了10倍左右</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>Benchmark Mode Cnt Score Error Units
Benchmark1.test1 thrpt 5 357337.402 ± 131498.372 ops/s
Benchmark1.test2 thrpt 5 394812.201 ± 434387.776 ops/s
Benchmark1.test3 thrpt 5 377967.137 ± 377008.086 ops/s
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>分析:</p> <p>在刚才的示例中doSum 方法是否内联会影响 elements 成员变量读取的优化:</p> <p>如果 doSum 方法内联了,刚才的 test1 方法会被优化成下面的样子(伪代码):</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Benchmark</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">test1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// elements 首次读取会缓存起来 -&gt; int[] local机器码级别缓存后续就不需要再访问 elements 成员变量了)</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> elements<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 后续 999 次 求长度 &lt;- local</span>
sum <span class="token operator">+=</span> elements<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// 1000 次取下标 i 的元素 &lt;- local</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>可以节省 1999 次 Field 读取操作</p> <p>但如果 doSum 方法没有内联,则不会进行上面的优化</p> <blockquote><p>练习:在内联情况下将 elements 添加 volatile 修饰符会发生什么?</p> <p>运行结果如下,发现方法一的吞吐量大大降低了</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>Benchmark Mode Cnt Score Error Units
Benchmark1.test1 thrpt 5 660532.339 ± 41637.563 ops/s
Benchmark1.test2 thrpt 5 3356062.311 ± 32060.956 ops/s
Benchmark1.test3 thrpt 5 3359952.483 ± 30073.397 ops/s
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div></blockquote> <blockquote><p><strong>Tip</strong>:</p> <p>这三种方法分别进行了优化</p> <ol><li>如果没有关闭方法内联,则虚拟机将自动进行优化</li> <li>使用了局部变量,避免多次向成员变量进行访问,进行了手动优化</li> <li>foreach 语法糖编译结果与 2 相同,也属于编译器优化</li></ol> <p><strong>注意</strong>:若要对这种类似的进行优化,可以考虑多使用局部变量。</p></blockquote> <h3 id="_3-2-反射优化"><a href="#_3-2-反射优化" class="header-anchor">#</a> 3.2 反射优化</h3> <p>运行以下反射代码,进行代码执行分析</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Reflect1</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;foo method&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
<span class="token class-name">Method</span> method <span class="token operator">=</span> <span class="token class-name">Reflect1</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token string">&quot;foo&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;=</span> <span class="token number">16</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">&quot;%d\t&quot;</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span>
method<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>in<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><p>在方法反射的 invoke 源码中,会发现反射调用是通过一个接口 <code>MethodAccessor</code> 来执行的</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@CallerSensitive</span>
<span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">Object</span> obj<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> args<span class="token punctuation">)</span>
<span class="token keyword">throws</span> <span class="token class-name">IllegalAccessException</span><span class="token punctuation">,</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">,</span>
<span class="token class-name">InvocationTargetException</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>override<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token class-name">Reflection</span><span class="token punctuation">.</span><span class="token function">quickCheckMemberAccess</span><span class="token punctuation">(</span>clazz<span class="token punctuation">,</span> modifiers<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> caller <span class="token operator">=</span> <span class="token class-name">Reflection</span><span class="token punctuation">.</span><span class="token function">getCallerClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">checkAccess</span><span class="token punctuation">(</span>caller<span class="token punctuation">,</span> clazz<span class="token punctuation">,</span> obj<span class="token punctuation">,</span> modifiers<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token class-name">MethodAccessor</span> ma <span class="token operator">=</span> methodAccessor<span class="token punctuation">;</span> <span class="token comment">// read volatile</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ma <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
ma <span class="token operator">=</span> <span class="token function">acquireMethodAccessor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> ma<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p><code>method.invoke(null)</code> 前面 0 ~ 15 次调用使用的是 <code>MethodAccessor</code><code>NativeMethodAccessorImpl</code> 实现,是个本地方法</p> <ul><li>步入到 <code>ReflectionFactory.inflationThreshold()</code> 中可以发现该值为 15是一个膨胀阈值就是执行本地方法反射的最大执行次数</li> <li>当超过了膨胀阈值之后,就会使用 ASM 动态生成的新实现代替本地实现,执行速度较本地快 20 倍左右</li></ul> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">class</span> <span class="token class-name">NativeMethodAccessorImpl</span> <span class="token keyword">extends</span> <span class="token class-name">MethodAccessorImpl</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">Method</span> method<span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">DelegatingMethodAccessorImpl</span> parent<span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> numInvocations<span class="token punctuation">;</span>
<span class="token class-name">NativeMethodAccessorImpl</span><span class="token punctuation">(</span><span class="token class-name">Method</span> var1<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>method <span class="token operator">=</span> var1<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">Object</span> var1<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> var2<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">,</span> <span class="token class-name">InvocationTargetException</span> <span class="token punctuation">{</span>
<span class="token comment">// 判断是否超过预设的膨胀阈值</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">++</span><span class="token keyword">this</span><span class="token punctuation">.</span>numInvocations <span class="token operator">&gt;</span> <span class="token class-name">ReflectionFactory</span><span class="token punctuation">.</span><span class="token function">inflationThreshold</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
<span class="token operator">!</span><span class="token class-name">ReflectUtil</span><span class="token punctuation">.</span><span class="token function">isVMAnonymousClass</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>method<span class="token punctuation">.</span><span class="token function">getDeclaringClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 使用 ASM 动态生成新的反射调用</span>
<span class="token class-name">MethodAccessorImpl</span> var3 <span class="token operator">=</span>
<span class="token punctuation">(</span><span class="token class-name">MethodAccessorImpl</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">MethodAccessorGenerator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">generateMethod</span><span class="token punctuation">(</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>method<span class="token punctuation">.</span><span class="token function">getDeclaringClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>method<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>method<span class="token punctuation">.</span><span class="token function">getParameterTypes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>method<span class="token punctuation">.</span><span class="token function">getReturnType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>method<span class="token punctuation">.</span><span class="token function">getExceptionTypes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>method<span class="token punctuation">.</span><span class="token function">getModifiers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>parent<span class="token punctuation">.</span><span class="token function">setDelegate</span><span class="token punctuation">(</span>var3<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token function">invoke0</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>method<span class="token punctuation">,</span> var1<span class="token punctuation">,</span> var2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">void</span> <span class="token function">setParent</span><span class="token punctuation">(</span><span class="token class-name">DelegatingMethodAccessorImpl</span> var1<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>parent <span class="token operator">=</span> var1<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">native</span> <span class="token class-name">Object</span> <span class="token function">invoke0</span><span class="token punctuation">(</span><span class="token class-name">Method</span> var0<span class="token punctuation">,</span> <span class="token class-name">Object</span> var1<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> var2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br></div></div><p>当调用到第 16 次从0开始算会采用运行时生成的类代替掉最初的实现可以通过 debug 得到 类名为 <code>sun.reflect.GeneratedMethodAccessor1</code></p> <img src="/jvm/1670569560207.png" alt="1670569560207" style="zoom:67%;"> <p>可以使用 arthas 工具来进行查看</p> <ul><li>进入到对应的运行进程</li> <li>输入命令 <code>jad sun.reflect.GeneratedMethodAccessor1</code> 进行反编译</li></ul> <img src="/jvm/1670570534000.png" alt="1670569967783" style="zoom:67%;"> <blockquote><p><strong>注意</strong></p> <p>通过查看 <code>ReflectionFactory</code> 源码可知</p> <ul><li><code>sun.reflect.noInflation</code> 可以用来禁用膨胀(直接生成 <code>GeneratedMethodAccessor1</code>,但首 次生成比较耗时,如果仅反射调用一次,不划算)</li> <li><code>sun.reflect.inflationThreshold</code> 可以修改膨胀阈值</li></ul></blockquote></div></section> <footer class="page-edit"><!----> <!----></footer> <div class="page-nav"><p class="inner"><span class="prev"><a href="/blogs/java/jvm/JVM-字节码技术.html" class="prev">
JVM之字节码技术
</a></span> <!----></p></div> <div class="comments-wrapper"><!----></div></main></div> <!----></div> <ul class="sub-sidebar sub-sidebar-wrapper" style="width:12rem;" data-v-b57cc07c data-v-7dd95ae2><li class="level-2" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_1-类加载阶段" class="sidebar-link reco-side-_1-类加载阶段" data-v-b57cc07c>1 类加载阶段</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_1-1-加载" class="sidebar-link reco-side-_1-1-加载" data-v-b57cc07c>1.1 加载</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_1-2-链接" class="sidebar-link reco-side-_1-2-链接" data-v-b57cc07c>1.2 链接</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_1-3-初始化" class="sidebar-link reco-side-_1-3-初始化" data-v-b57cc07c>1.3 初始化</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_1-4-练习" class="sidebar-link reco-side-_1-4-练习" data-v-b57cc07c>1.4 练习</a></li><li class="level-2" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_2-类加载器" class="sidebar-link reco-side-_2-类加载器" data-v-b57cc07c>2 类加载器</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_2-1-启动类加载器" class="sidebar-link reco-side-_2-1-启动类加载器" data-v-b57cc07c>2.1 启动类加载器</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_2-2-扩展类加载器" class="sidebar-link reco-side-_2-2-扩展类加载器" data-v-b57cc07c>2.2 扩展类加载器</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_2-3-双亲委派模式" class="sidebar-link reco-side-_2-3-双亲委派模式" data-v-b57cc07c>2.3 双亲委派模式</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_2-4-线程上下文类加载器" class="sidebar-link reco-side-_2-4-线程上下文类加载器" data-v-b57cc07c>2.4 线程上下文类加载器</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_2-5-自定义类加载器" class="sidebar-link reco-side-_2-5-自定义类加载器" data-v-b57cc07c>2.5 自定义类加载器</a></li><li class="level-2" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_3-运行期优化" class="sidebar-link reco-side-_3-运行期优化" data-v-b57cc07c>3 运行期优化</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_3-1-即时编译" class="sidebar-link reco-side-_3-1-即时编译" data-v-b57cc07c>3.1 即时编译</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E7%B1%BB%E5%8A%A0%E8%BD%BD.html#_3-2-反射优化" class="sidebar-link reco-side-_3-2-反射优化" data-v-b57cc07c>3.2 反射优化</a></li></ul></div></div></div><div class="global-ui"><div class="back-to-ceiling" style="right:1rem;bottom:6rem;width:2.5rem;height:2.5rem;border-radius:.25rem;line-height:2.5rem;display:none;" data-v-c6073ba8 data-v-c6073ba8><svg t="1574745035067" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5404" class="icon" data-v-c6073ba8><path d="M526.60727968 10.90185116a27.675 27.675 0 0 0-29.21455937 0c-131.36607665 82.28402758-218.69155461 228.01873535-218.69155402 394.07834331a462.20625001 462.20625001 0 0 0 5.36959153 69.94390903c1.00431239 6.55289093-0.34802892 13.13561351-3.76865779 18.80351572-32.63518765 54.11355614-51.75690182 118.55860487-51.7569018 187.94566865a371.06718723 371.06718723 0 0 0 11.50484808 91.98906777c6.53300375 25.50556257 41.68394495 28.14064038 52.69160883 4.22606766 17.37162448-37.73630017 42.14135425-72.50938081 72.80769204-103.21549295 2.18761121 3.04276886 4.15646224 6.24463696 6.40373557 9.22774369a1871.4375 1871.4375 0 0 0 140.04691725 5.34970492 1866.36093723 1866.36093723 0 0 0 140.04691723-5.34970492c2.24727335-2.98310674 4.21612437-6.18497483 6.3937923-9.2178004 30.66633723 30.70611158 55.4360664 65.4791928 72.80769147 103.21549355 11.00766384 23.91457269 46.15860503 21.27949489 52.69160879-4.22606768a371.15156223 371.15156223 0 0 0 11.514792-91.99901164c0-69.36717486-19.13165746-133.82216804-51.75690182-187.92578088-3.42062944-5.66790279-4.76302748-12.26056868-3.76865837-18.80351632a462.20625001 462.20625001 0 0 0 5.36959269-69.943909c-0.00994388-166.08943902-87.32547796-311.81420293-218.6915546-394.09823051zM605.93803103 357.87693858a93.93749974 93.93749974 0 1 1-187.89594924 6.1e-7 93.93749974 93.93749974 0 0 1 187.89594924-6.1e-7z" p-id="5405" data-v-c6073ba8></path><path d="M429.50777625 765.63860547C429.50777625 803.39355007 466.44236686 1000.39046097 512.00932183 1000.39046097c45.56695499 0 82.4922232-197.00623328 82.5015456-234.7518555 0-37.75494459-36.9345906-68.35043303-82.4922232-68.34111062-45.57627738-0.00932239-82.52019037 30.59548842-82.51086798 68.34111062z" p-id="5406" data-v-c6073ba8></path></svg></div></div></div>
<script src="/assets/js/app.049e1b5b.js" defer></script><script src="/assets/js/3.ff0e945d.js" defer></script><script src="/assets/js/1.1ced4111.js" defer></script><script src="/assets/js/21.2956f057.js" defer></script>
</body>
</html>