图片替换

This commit is contained in:
Dragon
2020-11-19 17:34:16 +08:00
parent 3923383a59
commit 0b29daa348
6 changed files with 136 additions and 130 deletions

View File

@@ -10,6 +10,7 @@ keywords: JVM虚拟机。
description: JVM系列-第10章-垃圾回收概述和相关算法。 description: JVM系列-第10章-垃圾回收概述和相关算法。
cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/logo.png' cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/logo.png'
top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg' top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg'
abbrlink: d54daa0f
date: 2020-11-16 18:14:02 date: 2020-11-16 18:14:02
--- ---
@@ -20,7 +21,7 @@ date: 2020-11-16 18:14:02
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0001.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0001.png">
1. Java 和 C++语言的区别就在于垃圾收集技术和内存动态分配上C++语言没有垃圾收集技术,需要程序员手动的收集。 1. Java 和 C++语言的区别就在于垃圾收集技术和内存动态分配上C++语言没有垃圾收集技术,需要程序员手动的收集。
@@ -102,7 +103,7 @@ date: 2020-11-16 18:14:02
**十几年前磁盘碎片整理的日子** **十几年前磁盘碎片整理的日子**
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0002.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0002.jpg">
@@ -174,7 +175,7 @@ date: 2020-11-16 18:14:02
### 应该关心哪些区域的回收? ### 应该关心哪些区域的回收?
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0003.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0003.png">
1. 垃圾收集器可以对年轻代回收,也可以对老年代回收,甚至是全栈和方法区的回收, 1. 垃圾收集器可以对年轻代回收,也可以对老年代回收,甚至是全栈和方法区的回收,
1. 其中,**Java堆是垃圾收集器的工作重点** 1. 其中,**Java堆是垃圾收集器的工作重点**
@@ -216,7 +217,7 @@ date: 2020-11-16 18:14:02
### 循环引用 ### 循环引用
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0004.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0004.png">
当p的指针断开的时候内部的引用形成一个循环计数器都还算1无法被回收这就是循环引用从而造成内存泄漏 当p的指针断开的时候内部的引用形成一个循环计数器都还算1无法被回收这就是循环引用从而造成内存泄漏
@@ -255,7 +256,7 @@ public class RefCountGC {
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0005.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0005.png">
* 如果不小心直接把`obj1.reference`和`obj2.reference`置为null。则在Java堆中的两块内存依然保持着互相引用无法被回收 * 如果不小心直接把`obj1.reference`和`obj2.reference`置为null。则在Java堆中的两块内存依然保持着互相引用无法被回收
@@ -353,7 +354,7 @@ Process finished with exit code 0
3. 如果目标对象没有任何引用链相连,则是不可达的,就意味着该对象己经死亡,可以标记为垃圾对象。 3. 如果目标对象没有任何引用链相连,则是不可达的,就意味着该对象己经死亡,可以标记为垃圾对象。
4. 在可达性分析算法中,只有能够被根对象集合直接或者间接连接的对象才是存活对象。 4. 在可达性分析算法中,只有能够被根对象集合直接或者间接连接的对象才是存活对象。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0006.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0006.png">
@@ -371,7 +372,7 @@ Process finished with exit code 0
- 基本数据类型对应的Class对象一些常驻的异常对象NullPointerException、OutofMemoryError系统类加载器。 - 基本数据类型对应的Class对象一些常驻的异常对象NullPointerException、OutofMemoryError系统类加载器。
7. 反映java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。 7. 反映java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0007.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0007.png">
@@ -453,7 +454,7 @@ Object 类中 finalize() 源码
**通过 JVisual VM 查看 Finalizer 线程** **通过 JVisual VM 查看 Finalizer 线程**
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0008.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0008.png">
@@ -579,7 +580,7 @@ MAT与JProfiler的GC Roots溯源
**方式一:命令行使用 jmap** **方式一:命令行使用 jmap**
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0009.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0009.png">
@@ -631,23 +632,23 @@ public class GCRootsTest {
1、先执行第一步然后停下来去生成此步骤dump文件 1、先执行第一步然后停下来去生成此步骤dump文件
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0010.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0010.png">
2、 点击【堆 Dump】 2、 点击【堆 Dump】
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0011.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0011.png">
3、右键 --\> 另存为即可 3、右键 --\> 另存为即可
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0012.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0012.jpg">
4、输入命令继续执行程序 4、输入命令继续执行程序
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0013.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0013.png">
5、我们接着捕获第二张堆内存快照 5、我们接着捕获第二张堆内存快照
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0014.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0014.jpg">
@@ -657,19 +658,19 @@ public class GCRootsTest {
> 点击Open Heap Dump也行 > 点击Open Heap Dump也行
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0015.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0015.png">
2、选择Java Basics --> GC Roots 2、选择Java Basics --> GC Roots
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0016.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0016.png">
3、第一次捕捉堆内存快照时GC Roots 中包含我们定义的两个局部变量,类型分别为 ArrayList 和 DateTotal:21 3、第一次捕捉堆内存快照时GC Roots 中包含我们定义的两个局部变量,类型分别为 ArrayList 和 DateTotal:21
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0017.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0017.jpg">
4、打开第二个dump文件第二次捕获内存快照时由于两个局部变量引用的对象被释放所以这两个局部变量不再作为 GC Roots ,从 Total Entries = 19 也可以看出(少了两个 GC Roots 4、打开第二个dump文件第二次捕获内存快照时由于两个局部变量引用的对象被释放所以这两个局部变量不再作为 GC Roots ,从 Total Entries = 19 也可以看出(少了两个 GC Roots
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0018.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0018.jpg">
@@ -716,13 +717,13 @@ public class GCRootsTest {
1、 1、
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0019.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0019.jpg">
2、 2、
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0020.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0020.png">
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0021.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0021.jpg">
可以发现颜色变绿了,可以动态的看变化 可以发现颜色变绿了,可以动态的看变化
@@ -730,11 +731,11 @@ public class GCRootsTest {
3、右击对象选择 Show Selection In Heap Walker单独的查看某个对象 3、右击对象选择 Show Selection In Heap Walker单独的查看某个对象
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0022.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0022.png">
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0023.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0023.png">
@@ -742,13 +743,13 @@ public class GCRootsTest {
点击Show Paths To GC Roots在弹出界面中选择默认设置即可 点击Show Paths To GC Roots在弹出界面中选择默认设置即可
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0024.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0024.jpg">
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0025.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0025.png">
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0026.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0026.png">
### JProfiler 分析 OOM ### JProfiler 分析 OOM
@@ -798,11 +799,11 @@ count = 6
1、看这个超大对象 1、看这个超大对象
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0027.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0027.png">
2、揪出 main() 线程中出问题的代码 2、揪出 main() 线程中出问题的代码
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0028.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0028.png">
@@ -837,7 +838,7 @@ count = 6
* 注意:标记的是被引用的对象,也就是可达对象,并非标记的是即将被清除的垃圾对象 * 注意:标记的是被引用的对象,也就是可达对象,并非标记的是即将被清除的垃圾对象
2. 清除Collector对堆内存从头到尾进行线性的遍历如果发现某个对象在其Header中没有标记为可达对象则将其回收 2. 清除Collector对堆内存从头到尾进行线性的遍历如果发现某个对象在其Header中没有标记为可达对象则将其回收
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0029.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0029.png">
@@ -876,7 +877,7 @@ count = 6
将活着的内存空间分为两块,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后清除正在使用的内存块中的所有对象,交换两个内存的角色,最后完成垃圾回收 将活着的内存空间分为两块,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后清除正在使用的内存块中的所有对象,交换两个内存的角色,最后完成垃圾回收
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0030.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0030.png">
新生代里面就用到了复制算法Eden区和S0区存活对象整体复制到S1区 新生代里面就用到了复制算法Eden区和S0区存活对象整体复制到S1区
@@ -906,7 +907,7 @@ count = 6
2. 老年代大量的对象存活,那么复制的对象将会有很多,效率会很低 2. 老年代大量的对象存活,那么复制的对象将会有很多,效率会很低
3. 在新生代对常规应用的垃圾回收一次通常可以回收70% - 99% 的内存空间。回收性价比很高。所以现在的商业虚拟机都是用这种收集算法回收新生代。 3. 在新生代对常规应用的垃圾回收一次通常可以回收70% - 99% 的内存空间。回收性价比很高。所以现在的商业虚拟机都是用这种收集算法回收新生代。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0031.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0031.png">
@@ -935,7 +936,7 @@ count = 6
2. 第二阶段将所有的存活对象压缩到内存的一端,按顺序排放。之后,清理边界外所有的空间。 2. 第二阶段将所有的存活对象压缩到内存的一端,按顺序排放。之后,清理边界外所有的空间。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0032.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0032.png">
@@ -1066,7 +1067,7 @@ A没有最好的算法只有最合适的算法
1. 一般来说在相同条件下堆空间越大一次GC时所需要的时间就越长有关GC产生的停顿也越长。为了更好地控制GC产生的停顿时间将一块大的内存区域分割成多个小块根据目标的停顿时间每次合理地回收若干个小区间而不是整个堆空间从而减少一次GC所产生的停顿。 1. 一般来说在相同条件下堆空间越大一次GC时所需要的时间就越长有关GC产生的停顿也越长。为了更好地控制GC产生的停顿时间将一块大的内存区域分割成多个小块根据目标的停顿时间每次合理地回收若干个小区间而不是整个堆空间从而减少一次GC所产生的停顿。
3. 分代算法将按照对象的生命周期长短划分成两个部分,分区算法将整个堆空间划分成连续的不同小区间。每一个小区间都独立使用,独立回收。这种算法的好处是可以控制一次回收多少个小区间。 3. 分代算法将按照对象的生命周期长短划分成两个部分,分区算法将整个堆空间划分成连续的不同小区间。每一个小区间都独立使用,独立回收。这种算法的好处是可以控制一次回收多少个小区间。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_010/0033.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_010/0033.png">

View File

@@ -10,6 +10,7 @@ keywords: JVM虚拟机。
description: JVM系列-第11章-垃圾回收相关概念。 description: JVM系列-第11章-垃圾回收相关概念。
cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/logo.png' cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/logo.png'
top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg' top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg'
abbrlink: 4d401a8b
date: 2020-11-17 12:33:24 date: 2020-11-17 12:33:24
--- ---
@@ -117,7 +118,7 @@ JVM参数
2、我也查过了大对象阈值的默认值 2、我也查过了大对象阈值的默认值
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_011/0001.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_011/0001.png">
我不太懂这个默认值为啥是0我猜测可能是代表什么比例目前也没有搜到相关的东西。这个不太重要暂时就没有太深究希望读者有知道的可以告知我一声。 我不太懂这个默认值为啥是0我猜测可能是代表什么比例目前也没有搜到相关的东西。这个不太重要暂时就没有太深究希望读者有知道的可以告知我一声。
@@ -185,11 +186,11 @@ Heap
1、来看看字节码实例方法局部变量表第一个变量肯定是 this 1、来看看字节码实例方法局部变量表第一个变量肯定是 this
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_011/0002.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_011/0002.png">
2、你有没有看到局部变量表的大小是 2。但是局部变量表里只有一个索引为0的啊那索引为1的是哪个局部变量呢实际上索引为1的位置是buffer在占用着执行 System.gc() 时,栈中还有 buffer 变量指向堆中的字节数组所以没有进行GC 2、你有没有看到局部变量表的大小是 2。但是局部变量表里只有一个索引为0的啊那索引为1的是哪个局部变量呢实际上索引为1的位置是buffer在占用着执行 System.gc() 时,栈中还有 buffer 变量指向堆中的字节数组所以没有进行GC
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_011/0003.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_011/0003.png">
3、那么这种代码块的情况什么时候会被GC呢我们来看第四个方法 3、那么这种代码块的情况什么时候会被GC呢我们来看第四个方法
@@ -217,11 +218,11 @@ A局部变量表长度为 2 这说明了出了代码块时buffer 就出
> 这点看不懂的可以看我前面的文章:虚拟机栈 --> Slot的重复利用 > 这点看不懂的可以看我前面的文章:虚拟机栈 --> Slot的重复利用
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_011/0004.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_011/0004.png">
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_011/0005.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_011/0005.png">
@@ -302,7 +303,7 @@ Heap
右边的图后期有一些对象不用了按道理应该断开引用但是存在一些链没有断开图示中的Forgotten Reference Memory Leak从而导致没有办法被回收。 右边的图后期有一些对象不用了按道理应该断开引用但是存在一些链没有断开图示中的Forgotten Reference Memory Leak从而导致没有办法被回收。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_011/0006.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_011/0006.png">
@@ -446,7 +447,7 @@ Process finished with exit code -1
2. 并发不是真正意义上的“同时进行”只是CPU把一个时间段划分成几个时间片段时间区间然后在这几个时间区间之间来回切换。由于CPU处理的速度非常快只要时间间隔处理得当即可让用户感觉是多个应用程序同时在进行 2. 并发不是真正意义上的“同时进行”只是CPU把一个时间段划分成几个时间片段时间区间然后在这几个时间区间之间来回切换。由于CPU处理的速度非常快只要时间间隔处理得当即可让用户感觉是多个应用程序同时在进行
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_011/0007.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_011/0007.png">
@@ -461,7 +462,7 @@ Process finished with exit code -1
3. 适合科学计算,后台处理等弱交互场景 3. 适合科学计算,后台处理等弱交互场景
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_011/0008.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_011/0008.png">
> **并发与并行的对比** > **并发与并行的对比**
@@ -482,7 +483,7 @@ Process finished with exit code -1
* 相较于并行的概念,单线程执行。 * 相较于并行的概念,单线程执行。
* 如果内存不够则程序暂停启动JVM垃圾回收器进行垃圾回收单线程 * 如果内存不够则程序暂停启动JVM垃圾回收器进行垃圾回收单线程
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_011/0009.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_011/0009.png">
@@ -492,7 +493,7 @@ Process finished with exit code -1
- 比如用户程序在继续运行而垃圾收集程序线程运行于另一个CPU上 - 比如用户程序在继续运行而垃圾收集程序线程运行于另一个CPU上
2. 典型垃圾回收器CMS、G1 2. 典型垃圾回收器CMS、G1
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_011/0010.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_011/0010.png">
@@ -551,7 +552,7 @@ Process finished with exit code -1
1、一般的垃圾回收算法至少会划分出两个年代年轻代和老年代。但是单纯的分代理论在垃圾回收的时候存在一个巨大的缺陷为了找到年轻代中的存活对象却不得不遍历整个老年代反过来也是一样的。 1、一般的垃圾回收算法至少会划分出两个年代年轻代和老年代。但是单纯的分代理论在垃圾回收的时候存在一个巨大的缺陷为了找到年轻代中的存活对象却不得不遍历整个老年代反过来也是一样的。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_011/0011.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_011/0011.png">
2、如果我们从年轻代开始遍历那么可以断定N, S, P, Q都是存活对象。但是V却不会被认为是存活对象其占据的内存会被回收了。这就是一个惊天的大漏洞因为U本身是老年代对象而且有外部引用指向它也就是说U是存活对象而U指向了V也就是说V也应该是存活对象才是而这都是因为我们只遍历年轻代对象 2、如果我们从年轻代开始遍历那么可以断定N, S, P, Q都是存活对象。但是V却不会被认为是存活对象其占据的内存会被回收了。这就是一个惊天的大漏洞因为U本身是老年代对象而且有外部引用指向它也就是说U是存活对象而U指向了V也就是说V也应该是存活对象才是而这都是因为我们只遍历年轻代对象
@@ -599,7 +600,7 @@ Process finished with exit code -1
4. 这4种引用强度依次逐渐减弱。除强引用外其他3种引用均可以在java.lang.ref包中找到它们的身影。如下图显示了这3种引用类型对应的类开发人员可以在应用程序中直接使用它们。 4. 这4种引用强度依次逐渐减弱。除强引用外其他3种引用均可以在java.lang.ref包中找到它们的身影。如下图显示了这3种引用类型对应的类开发人员可以在应用程序中直接使用它们。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_011/0012.png" > <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_011/0012.png" >
@@ -661,7 +662,7 @@ Hello,尚硅谷
`StringBuffer str = new StringBuffer("hello,尚硅谷");` `StringBuffer str = new StringBuffer("hello,尚硅谷");`
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_011/0013.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_011/0013.png">

View File

@@ -10,6 +10,7 @@ keywords: JVM虚拟机。
description: JVM系列-第6章-方法区。 description: JVM系列-第6章-方法区。
cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/logo.png' cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/logo.png'
top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg' top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg'
abbrlink: 136cd965
date: 2020-11-13 19:38:42 date: 2020-11-13 19:38:42
--- ---
@@ -24,7 +25,7 @@ date: 2020-11-13 19:38:42
ThreadLocal如何保证多个线程在并发环境下的安全性典型场景就是数据库连接管理以及会话管理。 ThreadLocal如何保证多个线程在并发环境下的安全性典型场景就是数据库连接管理以及会话管理。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0001.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0001.png">
**栈、堆、方法区的交互关系** **栈、堆、方法区的交互关系**
@@ -35,7 +36,7 @@ ThreadLocal如何保证多个线程在并发环境下的安全性典型场
3. 真正的 person 对象存放在 Java 堆中 3. 真正的 person 对象存放在 Java 堆中
4. 在 person 对象中,有个指针指向方法区中的 person 类型数据,表明这个 person 对象是用方法区中的 Person 类 new 出来的 4. 在 person 对象中,有个指针指向方法区中的 person 类型数据,表明这个 person 对象是用方法区中的 Person 类 new 出来的
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0002.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0002.png">
方法区的理解 方法区的理解
-------- --------
@@ -47,7 +48,7 @@ ThreadLocal如何保证多个线程在并发环境下的安全性典型场
1. 《Java虚拟机规范》中明确说明尽管所有的方法区在逻辑上是属于堆的一部分但一些简单的实现可能不会选择去进行垃圾收集或者进行压缩。但对于HotSpotJVM而言方法区还有一个别名叫做Non-Heap非堆目的就是要和堆分开。 1. 《Java虚拟机规范》中明确说明尽管所有的方法区在逻辑上是属于堆的一部分但一些简单的实现可能不会选择去进行垃圾收集或者进行压缩。但对于HotSpotJVM而言方法区还有一个别名叫做Non-Heap非堆目的就是要和堆分开。
3. 所以,**方法区可以看作是一块独立于Java堆的内存空间**。 3. 所以,**方法区可以看作是一块独立于Java堆的内存空间**。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0003.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0003.png">
@@ -87,7 +88,7 @@ public class MethodAreaDemo {
简单的程序加载了1600多个类 简单的程序加载了1600多个类
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0004.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0004.png">
@@ -103,7 +104,7 @@ public class MethodAreaDemo {
5. 永久代、元空间二者并不只是名字变了,内部结构也调整了 5. 永久代、元空间二者并不只是名字变了,内部结构也调整了
6. 根据《Java虚拟机规范》的规定如果方法区无法满足新的内存分配需求时将抛出OOM异常 6. 根据《Java虚拟机规范》的规定如果方法区无法满足新的内存分配需求时将抛出OOM异常
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0005.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0005.png">
@@ -120,7 +121,7 @@ public class MethodAreaDemo {
2. -XX:MaxPermsize来设定永久代最大可分配空间。32位机器默认是64M64位机器模式是82M 2. -XX:MaxPermsize来设定永久代最大可分配空间。32位机器默认是64M64位机器模式是82M
3. 当JVM加载的类信息容量超过了这个值会报异常OutofMemoryError:PermGen space。 3. 当JVM加载的类信息容量超过了这个值会报异常OutofMemoryError:PermGen space。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0006.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0006.png">
### JDK8及以后(元空间) ### JDK8及以后(元空间)
@@ -228,11 +229,11 @@ Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
#### 概念 #### 概念
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0007.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0007.png">
《深入理解Java虚拟机》书中对方法区Method Area存储内容描述如下它用于存储已被虚拟机加载的**类型信息、常量、静态变量、即时编译器编译后的代码缓存**等。 《深入理解Java虚拟机》书中对方法区Method Area存储内容描述如下它用于存储已被虚拟机加载的**类型信息、常量、静态变量、即时编译器编译后的代码缓存**等。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0008.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0008.png">
@@ -714,7 +715,7 @@ public static int count;
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0009.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0009.png">
1. 方法区,内部包含了运行时常量池 1. 方法区,内部包含了运行时常量池
2. 字节码文件内部包含了常量池。之前的字节码文件中已经看到了很多Constant pool的东西这个就是常量池 2. 字节码文件内部包含了常量池。之前的字节码文件中已经看到了很多Constant pool的东西这个就是常量池
@@ -728,7 +729,7 @@ public static int count;
1. 一个有效的字节码文件中除了包含类的版本信息、字段、方法以及接口等描述符信息外。还包含一项信息就是**常量池表****Constant Pool Table**),包括各种字面量和对类型、域和方法的符号引用。 1. 一个有效的字节码文件中除了包含类的版本信息、字段、方法以及接口等描述符信息外。还包含一项信息就是**常量池表****Constant Pool Table**),包括各种字面量和对类型、域和方法的符号引用。
2. 字面量: 10 “我是某某”这种数字和字符串都是字面量 2. 字面量: 10 “我是某某”这种数字和字符串都是字面量
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0010.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0010.png">
**为什么需要常量池?** **为什么需要常量池?**
@@ -749,7 +750,7 @@ public static int count;
2. 比如说我们这个文件中有6个地方用到了"hello"这个字符串如果不用常量池就需要在6个地方全写一遍造成臃肿。我们可以将"hello"等所需用到的结构信息记录在常量池中,并通过**引用的方式**,来加载、调用所需的结构 2. 比如说我们这个文件中有6个地方用到了"hello"这个字符串如果不用常量池就需要在6个地方全写一遍造成臃肿。我们可以将"hello"等所需用到的结构信息记录在常量池中,并通过**引用的方式**,来加载、调用所需的结构
4. 这里的代码量其实很少了,如果代码多的话,引用的结构将会更多,这里就需要用到常量池了。 4. 这里的代码量其实很少了,如果代码多的话,引用的结构将会更多,这里就需要用到常量池了。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0011.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0011.png">
**常量池中有啥?** **常量池中有啥?**
@@ -924,69 +925,69 @@ SourceFile: "MethodAreaDemo.java"
1、初始状态 1、初始状态
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0012.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0012.png">
2、首先将操作数500压入操作数栈中 2、首先将操作数500压入操作数栈中
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0013.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0013.png">
3、然后操作数 500 从操作数栈中取出,存储到局部变量表中索引为 1 的位置 3、然后操作数 500 从操作数栈中取出,存储到局部变量表中索引为 1 的位置
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0014.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0014.png">
4、 4、
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0015.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0015.png">
5、 5、
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0016.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0016.png">
6、 6、
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0017.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0017.png">
7、 7、
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0018.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0018.png">
8、 8、
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0019.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0019.png">
9、 9、
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0020.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0020.png">
10、 10、
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0021.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0021.png">
11、图片写错了是#25和#26获得System类 11、图片写错了是#25和#26获得System类
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0022.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0022.png">
12、 12、
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0023.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0023.png">
13、 13、
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0024.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0024.png">
15、执行加法运算后将计算结果放在操作数栈顶 15、执行加法运算后将计算结果放在操作数栈顶
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0025.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0025.png">
16、就是真正的打印 16、就是真正的打印
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0026.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0026.png">
17、 17、
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0027.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0027.png">
@@ -1021,7 +1022,7 @@ SourceFile: "MethodAreaDemo.java"
方法区由永久代实现,使用 JVM 虚拟机内存(虚拟的内存) 方法区由永久代实现,使用 JVM 虚拟机内存(虚拟的内存)
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0028.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0028.png">
@@ -1029,7 +1030,7 @@ SourceFile: "MethodAreaDemo.java"
方法区由永久代实现,使用 JVM 虚拟机内存 方法区由永久代实现,使用 JVM 虚拟机内存
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0029.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0029.png">
@@ -1037,7 +1038,7 @@ SourceFile: "MethodAreaDemo.java"
方法区由元空间实现,使用物理机本地内存 方法区由元空间实现,使用物理机本地内存
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0030.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0030.png">
@@ -1095,15 +1096,15 @@ public class StaticFieldTest {
JDK6环境下 JDK6环境下
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0031.png" alt="image-20201113224231761" /> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0031.png" alt="image-20201113224231761" />
JDK7环境下 JDK7环境下
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0032.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0032.png">
JDK8环境 JDK8环境
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0033.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0033.png">
@@ -1150,7 +1151,7 @@ public class StaticObjTest {
4、测试发现三个对象的数据在内存中的地址都落在Eden区范围内所以结论**只要是对象实例必然会在Java堆中分配**。 4、测试发现三个对象的数据在内存中的地址都落在Eden区范围内所以结论**只要是对象实例必然会在Java堆中分配**。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0034.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0034.png">
> 1、0x00007f32c7800000(Eden区的起始地址) ---- 0x00007f32c7b50000(Eden区的终止地址) > 1、0x00007f32c7800000(Eden区的起始地址) ---- 0x00007f32c7b50000(Eden区的终止地址)
> >
@@ -1162,7 +1163,7 @@ public class StaticObjTest {
5、接着找到了一个引用该staticObj对象的地方是在一个java.lang.Class的实例里并且给出了这个实例的地址通过Inspector查看该对象实例可以清楚看到这确实是一个java.lang.Class类型的对象实例里面有一个名为staticobj的实例字段 5、接着找到了一个引用该staticObj对象的地方是在一个java.lang.Class的实例里并且给出了这个实例的地址通过Inspector查看该对象实例可以清楚看到这确实是一个java.lang.Class类型的对象实例里面有一个名为staticobj的实例字段
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0035.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0035.png">
从《Java虚拟机规范》所定义的概念模型来看所有Class相关的信息都应该存放在方法区之中但方法区该如何实现《Java虚拟机规范》并未做出规定这就成了一件允许不同虚拟机自己灵活把握的事情。JDK7及其以后版本的HotSpot虚拟机选择把静态变量与类型在Java语言一端的映射Class对象存放在一起**存储于Java堆之中**,从我们的实验中也明确验证了这一点 从《Java虚拟机规范》所定义的概念模型来看所有Class相关的信息都应该存放在方法区之中但方法区该如何实现《Java虚拟机规范》并未做出规定这就成了一件允许不同虚拟机自己灵活把握的事情。JDK7及其以后版本的HotSpot虚拟机选择把静态变量与类型在Java语言一端的映射Class对象存放在一起**存储于Java堆之中**,从我们的实验中也明确验证了这一点
@@ -1217,7 +1218,7 @@ public class StaticObjTest {
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0036.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0036.png">
@@ -1271,7 +1272,7 @@ public class BufferTest {
直接占用了 1G 的本地内存 直接占用了 1G 的本地内存
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0037.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0037.jpg">
@@ -1281,13 +1282,13 @@ public class BufferTest {
原来采用BIO的架构在读写本地文件时我们需要从用户态切换成内核态 原来采用BIO的架构在读写本地文件时我们需要从用户态切换成内核态
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0038.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0038.png">
**直接缓冲区NIO** **直接缓冲区NIO**
NIO 直接操作物理磁盘,省去了中间过程 NIO 直接操作物理磁盘,省去了中间过程
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0039.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0039.png">
### 直接内存与 OOM ### 直接内存与 OOM
@@ -1351,7 +1352,7 @@ Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_006/0040.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_006/0040.jpg">

View File

@@ -10,6 +10,7 @@ keywords: JVM虚拟机。
description: JVM系列-第7章-对象的实例化内存布局与访问定位。 description: JVM系列-第7章-对象的实例化内存布局与访问定位。
cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/logo.png' cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/logo.png'
top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg' top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg'
abbrlink: debff71a
date: 2020-11-14 19:38:42 date: 2020-11-14 19:38:42
--- ---
@@ -36,7 +37,7 @@ date: 2020-11-14 19:38:42
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_007/0001.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_007/0001.png">
### 对象创建的方式 ### 对象创建的方式
@@ -211,7 +212,7 @@ class Account{
对象的内存布局 对象的内存布局
--------- ---------
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_007/0002.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_007/0002.png">
@@ -242,7 +243,7 @@ class Account{
图解内存布局 图解内存布局
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_007/0003.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_007/0003.png">
@@ -251,7 +252,7 @@ class Account{
**JVM是如何通过栈帧中的对象引用访问到其内部的对象实例呢** **JVM是如何通过栈帧中的对象引用访问到其内部的对象实例呢**
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_007/0004.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_007/0004.png">
定位通过栈上reference访问 定位通过栈上reference访问
@@ -262,7 +263,7 @@ class Account{
1. 缺点:在堆空间中开辟了一块空间作为句柄池,句柄池本身也会占用空间;通过两次指针访问才能访问到堆中的对象,效率低 1. 缺点:在堆空间中开辟了一块空间作为句柄池,句柄池本身也会占用空间;通过两次指针访问才能访问到堆中的对象,效率低
2. 优点reference中存储稳定句柄地址对象被移动垃圾收集时移动对象很普遍时只会改变句柄中实例数据指针即可reference本身不需要被修改 2. 优点reference中存储稳定句柄地址对象被移动垃圾收集时移动对象很普遍时只会改变句柄中实例数据指针即可reference本身不需要被修改
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_007/0005.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_007/0005.png">
@@ -271,4 +272,4 @@ class Account{
1. 优点:直接指针是局部变量表中的引用,直接指向堆中的实例,在对象实例中有类型指针,指向的是方法区中的对象类型数据 1. 优点:直接指针是局部变量表中的引用,直接指向堆中的实例,在对象实例中有类型指针,指向的是方法区中的对象类型数据
2. 缺点:对象被移动(垃圾收集时移动对象很普遍)时需要修改 reference 的值 2. 缺点:对象被移动(垃圾收集时移动对象很普遍)时需要修改 reference 的值
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_007/0006.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_007/0006.png">

View File

@@ -10,6 +10,7 @@ keywords: JVM虚拟机。
description: JVM系列-第8章-执行引擎。 description: JVM系列-第8章-执行引擎。
cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/logo.png' cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/logo.png'
top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg' top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg'
abbrlink: 408712f4
date: 2020-11-15 19:48:42 date: 2020-11-15 19:48:42
--- ---
@@ -23,7 +24,7 @@ date: 2020-11-15 19:48:42
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0001.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0001.png">
### 执行引擎概述 ### 执行引擎概述
@@ -34,7 +35,7 @@ date: 2020-11-15 19:48:42
3. JVM的主要任务是负责**装载字节码到其内部**但字节码并不能够直接运行在操作系统之上因为字节码指令并非等价于本地机器指令它内部包含的仅仅只是一些能够被JVM所识别的字节码指令、符号表以及其他辅助信息。 3. JVM的主要任务是负责**装载字节码到其内部**但字节码并不能够直接运行在操作系统之上因为字节码指令并非等价于本地机器指令它内部包含的仅仅只是一些能够被JVM所识别的字节码指令、符号表以及其他辅助信息。
4. 那么如果想要让一个Java程序运行起来执行引擎Execution Engine的任务就是**将字节码指令解释/编译为对应平台上的本地机器指令才可以**。简单来说JVM中的执行引擎充当了将高级语言翻译为机器语言的译者。 4. 那么如果想要让一个Java程序运行起来执行引擎Execution Engine的任务就是**将字节码指令解释/编译为对应平台上的本地机器指令才可以**。简单来说JVM中的执行引擎充当了将高级语言翻译为机器语言的译者。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0002.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0002.png">
1、前端编译从Java程序员-字节码文件的这个过程叫前端编译 1、前端编译从Java程序员-字节码文件的这个过程叫前端编译
@@ -51,7 +52,7 @@ date: 2020-11-15 19:48:42
3. 当然方法在执行的过程中执行引擎有可能会通过存储在局部变量表中的对象引用准确定位到存储在Java堆区中的对象实例信息以及通过对象头中的元数据指针定位到目标对象的类型信息。 3. 当然方法在执行的过程中执行引擎有可能会通过存储在局部变量表中的对象引用准确定位到存储在Java堆区中的对象实例信息以及通过对象头中的元数据指针定位到目标对象的类型信息。
4. 从外观上来看所有的Java虚拟机的执行引擎输入、处理、输出都是一致的输入的是字节码二进制流处理过程是字节码解析执行、即时编译的等效过程输出的是执行过程。 4. 从外观上来看所有的Java虚拟机的执行引擎输入、处理、输出都是一致的输入的是字节码二进制流处理过程是字节码解析执行、即时编译的等效过程输出的是执行过程。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0003.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0003.png">
@@ -71,18 +72,18 @@ Java代码编译和执行过程
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0004.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0004.png">
3. javac编译器前端编译器流程图如下所示 3. javac编译器前端编译器流程图如下所示
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0005.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0005.png">
4. Java字节码的执行是由JVM执行引擎来完成流程图如下所示 4. Java字节码的执行是由JVM执行引擎来完成流程图如下所示
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0006.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0006.png">
@@ -105,7 +106,7 @@ Java代码编译和执行过程
**用图总结一下** **用图总结一下**
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0007.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0007.png">
机器码 指令 汇编语言 机器码 指令 汇编语言
------------- -------------
@@ -164,7 +165,7 @@ Java代码编译和执行过程
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0008.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0008.png">
@@ -193,7 +194,7 @@ Java代码编译和执行过程
2. 汇编过程:实际上指把汇编语言代码翻译成目标机器指令的过程。 2. 汇编过程:实际上指把汇编语言代码翻译成目标机器指令的过程。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0009.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0009.png">
@@ -211,7 +212,7 @@ Java代码编译和执行过程
3. 当一条字节码指令被解释执行完成后接着再根据PC寄存器中记录的下一条需要被执行的字节码指令执行解释操作。 3. 当一条字节码指令被解释执行完成后接着再根据PC寄存器中记录的下一条需要被执行的字节码指令执行解释操作。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0010.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0010.png">
@@ -288,7 +289,7 @@ Java代码编译和执行过程
2. 在生产环境发布过程中以分批的方式进行发布根据机器数量划分成多个批次每个批次的机器数至多占到整个集群的1/8。曾经有这样的故障案例某程序员在发布平台进行分批发布在输入发布总批数时误填写成分为两批发布。如果是热机状态在正常情况下一半的机器可以勉强承载流量但由于刚启动的JVM均是解释执行还没有进行热点代码统计和JIT动态编译导致机器启动之后当前1/2发布成功的服务器马上全部宕机此故障说明了JIT的存在。—**阿里团队** 2. 在生产环境发布过程中以分批的方式进行发布根据机器数量划分成多个批次每个批次的机器数至多占到整个集群的1/8。曾经有这样的故障案例某程序员在发布平台进行分批发布在输入发布总批数时误填写成分为两批发布。如果是热机状态在正常情况下一半的机器可以勉强承载流量但由于刚启动的JVM均是解释执行还没有进行热点代码统计和JIT动态编译导致机器启动之后当前1/2发布成功的服务器马上全部宕机此故障说明了JIT的存在。—**阿里团队**
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0011.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0011.png">
@@ -317,7 +318,7 @@ public class JITTest {
通过 JVisualVM 查看 JIT 编译器执行的编译次数 通过 JVisualVM 查看 JIT 编译器执行的编译次数
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0012.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0012.png">
@@ -369,7 +370,7 @@ public class JITTest {
* 如果已超过阈值,那么将会向即时编译器提交一个该方法的代码编译请求。 * 如果已超过阈值,那么将会向即时编译器提交一个该方法的代码编译请求。
* 如果未超过阈值,则使用解释器对字节码文件解释执行 * 如果未超过阈值,则使用解释器对字节码文件解释执行
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0013.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0013.png">
@@ -387,7 +388,7 @@ public class JITTest {
它的作用是统计一个方法中循环体代码执行的次数在字节码中遇到控制流向后跳转的指令称为“回边”Back Edge。显然建立回边计数器统计的目的就是为了触发OSR编译。 它的作用是统计一个方法中循环体代码执行的次数在字节码中遇到控制流向后跳转的指令称为“回边”Back Edge。显然建立回边计数器统计的目的就是为了触发OSR编译。
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0014.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0014.png">
@@ -401,7 +402,7 @@ public class JITTest {
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_008/0015.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_008/0015.png">

View File

@@ -10,6 +10,7 @@ keywords: JVM虚拟机。
description: JVM系列-第9章-StringTable(字符串常量池)。 description: JVM系列-第9章-StringTable(字符串常量池)。
cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/logo.png' cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/logo.png'
top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg' top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg'
abbrlink: ee2ba71e
date: 2020-11-16 12:38:02 date: 2020-11-16 12:38:02
--- ---
@@ -166,11 +167,11 @@ str 的内容并没有变“test ok” 位于字符串常量池中的另一
4. 在JDK7中StringTable的长度默认值是60013StringTablesize设置没有要求 4. 在JDK7中StringTable的长度默认值是60013StringTablesize设置没有要求
5. 在JDK8中StringTable的长度默认值是60013StringTable可以设置的最小值为1009 5. 在JDK8中StringTable的长度默认值是60013StringTable可以设置的最小值为1009
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0001.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0001.png">
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0002.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0002.png">
@@ -276,11 +277,11 @@ String 的内存分配
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0003.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0003.png">
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0004.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0004.png">
@@ -382,23 +383,23 @@ public class StringTest4 {
1、程序启动时已经加载了 2293 个字符串常量 1、程序启动时已经加载了 2293 个字符串常量
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0005.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0005.png">
2、加载了一个换行符println所以多了一个 2、加载了一个换行符println所以多了一个
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0006.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0006.jpg">
3、加载了字符串常量 “1”~“9” 3、加载了字符串常量 “1”~“9”
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0007.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0007.jpg">
4、加载字符串常量 “10” 4、加载字符串常量 “10”
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0008.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0008.jpg">
5、之后的字符串"1" 到 "10"不会再次加载 5、之后的字符串"1" 到 "10"不会再次加载
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0009.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0009.png">
@@ -425,7 +426,7 @@ class Memory {
分析运行时内存foo() 方法是实例方法,其实图中少了一个 this 局部变量) 分析运行时内存foo() 方法是实例方法,其实图中少了一个 this 局部变量)
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0010.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0010.png">
@@ -493,7 +494,7 @@ class Memory {
IDEA 反编译 class 文件后,来看这个问题 IDEA 反编译 class 文件后,来看这个问题
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0011.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0011.png">
@@ -929,7 +930,7 @@ public class StringNewTest {
5. `23 ldc #8 <b>` :在字符串常量池中放入 “b”如果之前字符串常量池中没有 “b” 的话) 5. `23 ldc #8 <b>` :在字符串常量池中放入 “b”如果之前字符串常量池中没有 “b” 的话)
6. `31 invokevirtual #9 <java/lang/StringBuilder.toString>` :调用 StringBuilder 的 toString() 方法,会生成一个 String 对象 6. `31 invokevirtual #9 <java/lang/StringBuilder.toString>` :调用 StringBuilder 的 toString() 方法,会生成一个 String 对象
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0012.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0012.png">
@@ -988,13 +989,13 @@ JDK6 :正常眼光判断即可
* new String() 即在堆中 * new String() 即在堆中
* str.intern() 则把字符串放入常量池中 * str.intern() 则把字符串放入常量池中
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0013.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0013.png">
JDK7及后续版本**注意大坑** JDK7及后续版本**注意大坑**
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0014.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0014.png">
@@ -1053,11 +1054,11 @@ public class StringExer1 {
**JDK6** **JDK6**
![image-20201116113423492](https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0015.png) ![image-20201116113423492](https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0015.png)
**JDK7/8** **JDK7/8**
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0016.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0016.png">
@@ -1080,7 +1081,7 @@ public class StringExer1 {
} }
``` ```
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0017.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0017.png">
**练习3** **练习3**
@@ -1169,11 +1170,11 @@ public class StringIntern2 {
arr[i] = new String(String.valueOf(data[i % data.length])); arr[i] = new String(String.valueOf(data[i % data.length]));
``` ```
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0018.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0018.png">
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0019.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0019.png">
2、使用 intern() 方法:由于数组中字符串的引用都指向字符串常量池中的字符串,所以程序需要维护的 String 对象更少,内存占用也更低 2、使用 intern() 方法:由于数组中字符串的引用都指向字符串常量池中的字符串,所以程序需要维护的 String 对象更少,内存占用也更低
@@ -1182,11 +1183,11 @@ arr[i] = new String(String.valueOf(data[i % data.length]));
arr[i] = new String(String.valueOf(data[i % data.length])).intern(); arr[i] = new String(String.valueOf(data[i % data.length])).intern();
``` ```
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0020.png" > <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0020.png" >
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0021.png"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0021.png">
@@ -1218,11 +1219,11 @@ public class StringGCTest {
* Number of entries 和 Number of literals 明显没有 100000 * Number of entries 和 Number of literals 明显没有 100000
* 以上两点均说明 StringTable 区发生了垃圾回收 * 以上两点均说明 StringTable 区发生了垃圾回收
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0022.jpg"> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0022.jpg">
<img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img/JVM/chapter_009/0023.jpg"/> <img src="https://cdn.jsdelivr.net/gh/youthlql/lql_img_002/JVM/chapter_009/0023.jpg"/>