- 新增 .drone.yml 文件用于定义 CI/CD 流程 - 配置了基于 Docker 的部署步骤 - 设置了工作区和卷映射以支持持久化数据 - 添加了构建准备阶段和 Docker 部署阶段 - 定义了环境变量和代理设置 - 配置了 artifacts 目录的处理逻辑 - 添加了 timezone 映射以确保时间同步 - 设置了 docker.sock 映射以支持 Docker in Docker
650 lines
172 KiB
HTML
650 lines
172 KiB
HTML
<!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">></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">"main"</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">"qwe"</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">"asd"</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 -> b
|
||
5: new #3 // class java/lang/String
|
||
8: dup
|
||
9: ldc #4 // <- "asd"
|
||
11: invokespecial #5 // Method java/lang/String."<init>":(Ljava/lang/String;)V
|
||
14: putstatic #6 // "asd" -> 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"><</span><span class="token operator">?</span><span class="token punctuation">></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">"com.zhuhjay.demo4.C"</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<?> aClass = classLoader.loadClass("com.zhuhjay.demo4.C");</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><clinit>()V</code></h4> <p>初始化即调用 <code><clinit>()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("com.zhuhjay.demo4.B")</code> 会加载类B以及父类A,但不会触发初始化</li> <li><code>Class.forName("com.zhuhjay.demo4.B", 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("com.zhuhjay.demo4.B")</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">"main init"</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">"com.zhuhjay.demo4.B"</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">"com.zhuhjay.demo4.B"</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">"com.zhuhjay.demo4.B"</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">"a init"</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">"b init"</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">"qwe"</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">"E init"</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">"LazyHolder init"</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">"test method"</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>在加载一个类时,首先会向上级的类加载器"询问"是否可以进行类的加载,如果上级加载器可以加载,则由上级加载器加载,否则由 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"><</span><span class="token operator">?</span><span class="token punctuation">></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">"com.zhuhjay.demo4.F"</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">"Bootstrap F init"</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:<new bootclasspath></code></li> <li><code>java -Xbootclasspath/a:<追加路径></code>:后追加</li> <li><code>java -Xbootclasspath/p:<追加路径></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">"ext classpath G init"</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"><</span><span class="token operator">?</span><span class="token punctuation">></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">"com.zhuhjay.demo4.G"</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">"classpath G init"</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失效,印证了双亲委派(启动>扩展>应用>自定义)</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"><</span><span class="token operator">?</span><span class="token punctuation">></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"><</span><span class="token operator">?</span><span class="token punctuation">></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("com.mysql.jdbc.Driver");</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("com.mysql.jdbc.Driver");</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">"jdbc:mysql:///test?useSSL=false"</span><span class="token punctuation">,</span> <span class="token string">"root"</span><span class="token punctuation">,</span> <span class="token string">"root"</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">"select * from user"</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">"username"</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"><</span><span class="token class-name">DriverInfo</span><span class="token punctuation">></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"><</span><span class="token punctuation">></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">"JDBC DriverManager initialized"</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"><</span><span class="token class-name">String</span><span class="token punctuation">></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">"jdbc.drivers"</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"><</span><span class="token class-name">Void</span><span class="token punctuation">></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"><</span><span class="token class-name">Driver</span><span class="token punctuation">></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"><</span><span class="token class-name">Driver</span><span class="token punctuation">></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">"DriverManager.initialize: jdbc.drivers = "</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">""</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">":"</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">"number of Drivers:"</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">"DriverManager.Initialize: loading "</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">"DriverManager.Initialize: load failed: "</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"><</span><span class="token class-name">Driver</span><span class="token punctuation">></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"><</span><span class="token class-name">Driver</span><span class="token punctuation">></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"><</span><span class="token class-name">S</span><span class="token punctuation">></span></span> <span class="token class-name">ServiceLoader</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">S</span><span class="token punctuation">></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"><</span><span class="token class-name">S</span><span class="token punctuation">></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"><</span><span class="token operator">?</span><span class="token punctuation">></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">"Provider "</span> <span class="token operator">+</span> cn <span class="token operator">+</span> <span class="token string">" not found"</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">"Provider "</span> <span class="token operator">+</span> cn <span class="token operator">+</span> <span class="token string">" not a subtype"</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">"Provider "</span> <span class="token operator">+</span> cn <span class="token operator">+</span> <span class="token string">" could not be instantiated"</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"><</span><span class="token operator">?</span><span class="token punctuation">></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">"G:\\classpath\\"</span> <span class="token operator">+</span> name <span class="token operator">+</span> <span class="token string">".class"</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">"类文件未找到"</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"><</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"><</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">"%d\t%d\n"</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 < C1 < 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"><</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"><</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">"%d\t%d\n"</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"><</span>dependency</span><span class="token punctuation">></span></span>
|
||
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>groupId</span><span class="token punctuation">></span></span>org.apache.commons<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>groupId</span><span class="token punctuation">></span></span>
|
||
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>artifactId</span><span class="token punctuation">></span></span>commons-math3<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>artifactId</span><span class="token punctuation">></span></span>
|
||
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>version</span><span class="token punctuation">></span></span>3.6.1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>version</span><span class="token punctuation">></span></span>
|
||
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>dependency</span><span class="token punctuation">></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"><</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"><</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"><</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 首次读取会缓存起来 -> 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"><</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 次 求长度 <- 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 的元素 <- 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">"foo method"</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">"foo"</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"><=</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">"%d\t"</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"><</span><span class="token operator">?</span><span class="token punctuation">></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">></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">&&</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>
|