最为一个java的初学者,其实可以不用太细致的学习java虚拟机,不过如果你是有一定的工作经验了,那JVM绝对是一个不应该绕开的点。具体的讲解可以参考周志明的《深入理解Java虚拟机》,如果是深度学习,建议还是看书。如果是作为了解大致,可以看看网上的视频,再来点博客差不多了。各个视频针对的JDK版本记住要看清楚,每个版本的JDK都或多或少有些差别,不要迷了眼。
文章目录
-
- 1、JVM概述
-
- 1.1、JVM位置
- 1.2、JVM体系结构
- 2、类加载器
-
- 2.1、模板类
- 2.2、类加载器的分类
- 3、沙箱安全机制
- 4、Native
- 5、PC寄存器
- 6、方法区
- 7、栈
- 8、三种不同的JVM
- 9、堆(重点)
-
- 9.1、新生区、老年区、永久区
- 9.2、对内存调优
- 9.3、GC垃圾回收
- 10、JMM
- 11、思维导图
1、JVM概述
1.1、JVM位置
我们都知道java是一个跨平台的语言,其跨平台的特性则是由于虚拟机的存在。
那JVM虚拟机到底在哪里呢?
我们的OS系统是部署在计算机硬件之上,我们的JVM则是部署在OS之上,再往上走,就是我们编写程序了。
1.2、JVM体系结构
我们程序的执行顺序是:我们编写的.java文件经过编译生成.class文件,然后再将我们的.class文件交给类加载器,然后再执行相应的操作。
这个图有些笼统,不过大致的体系结构就是这样,可以当作一个入门的体系结构图示
我经常在网上看到内存调优这个关键词,它更多的指的位置就是在对JVM中堆内存的调节。
2、类加载器
2.1、模板类
在java的进阶阶段,我们学习过反射,我们也都知道,所有的对象都是来自于一个类模板的Class。就好比一个Student类所创建的所有的对象,都来自于Student.class这个模板,这些所有创建出来的对象,都来自同一个地方。
2.2、类加载器的分类
随着JDK版本的变化,可能名称有些许出入
1、根加载器
2、扩展加载器
3、系统加载器
4、自定义加载器
当然这里还出现了一个很重要的双亲委派机制
3、沙箱安全机制
java用来保证程序安全引入的一种安全机制
4、Native
结合我们类加载器的知识点,凡是带有native关键字的,都说明这是java作用范围达不到的,它回去调用底层的C语言的库。
带有native关键字的方法就会进入到本地方法栈,其他的会进入java栈
本地方法接口(Native Interface):起初是为了融合C/C++,现在大多可用于驱动底层的硬件
本地方法栈(Native Method Stack):在本地方法栈中登记native方法,在执行引擎的时候加载本地库(Native Libraies)
5、PC寄存器
又名程序计数器Program Counter Register
PC寄存器为每一个线程所私有,占用内存十分小。用于记录各个线程正在执行的字节码指令地址。
6、方法区
该区域可以与PC寄存器形成鲜明的对比,它是被线程所共享。
我们常见的static、final、Class模板、常量池都存在于方法区。
7、栈
我们一想到栈首先应该想到的就是与它齐名的队列。
栈(木桶):先进后出
队列(水管):先进先出
栈中存放的东西:八大基本类型 + 对象的引用 + 实例的方法
当栈满了以后,就会出发栈满异常StackOverflowError
我们还有一个堆没有学习,学习玩堆以后,我们对于实例化一个对象,并且赋值调用的整个流程,心里应该是要有一个流程图了。
8、三种不同的JVM
- Sun:HotSpot(我们使用的)
- BEA:JRockit
- IBM:J9 VM
9、堆(重点)
我们前面说了基本上的JVM调优,指的就是堆调优
堆内存主要分为:新生区(伊甸园区)、养老区、永久区
9.1、新生区、老年区、永久区
对象最开始产生的地方是伊甸园区,当伊甸园区满了以后就会触发第一次GC(轻GC),存活下来的对象就会进入到幸存者区。当幸存者区也满了以后,就会再触发GC(重GC),然后依然存活的对象就会进入养老区
如果养老区满了以后就会报堆满异常OOM:
java.lang.OutOfMemoryError:Java heap space
当然,JDK不同的版本,具体的细节又有些差别,特别是名字
我的观点是,现在公司大部分使用的是JDK1.8,我们要做的就是记住1.8的就好了。但是巧就巧再没有专门说1.8的书,《深入理解java虚拟机》的第二版是JDK1.7,第三版是JDK12,13左右…那就只有官方文档加实践了。
9.2、对内存调优
我们前面说了,轻GC和重GC是可以用来处理堆内存的垃圾对象的。那么多久用一次轻GC?多久又用一次重GC?甚至是堆内存异常的时候,我们怎么排查呢?
所以对内存调优就是为了排查出异常,排查方式可分为两种:
- 使用Debug一行一行看
- 使用内存快照分析工具,如MAT、Jprofiler
9.3、GC垃圾回收
垃圾回收算法有哪些?
复制算法、标记清除算法、标记压缩算法
==复制算法:==伊甸园区的对象总是进入幸存区的from区,与此同时,幸存区的to区的数据也进入from区(幸存区的from区和to区是随时变化的)。所以每次伊甸园区的数据进入from区的时候,该区总是空的。
==标记清除算法:==对所有的对象进行扫描,然后对活着的对象进行标记,第二次扫描的时候,对于没有标记的对象进行清除。
==标记压缩算法:==在标记清除算法的基础上,我们被清除的兑现过的空间位置是不连续的,就会产生内存碎片。此算法主要是讲空间进行压缩,让存活的对象进行移动,是内存碎片变成大的内存空间。
内存效率:复制算法 > 标记清除算法 > 标记压缩算法(时间复杂度)
内存整齐度:复制算法 = 标记压缩算法 > 标记清除算法
内存利用率:标记压缩算法 = 标记清除算法 > 复制算法
没有最好的算法,只有最合适的算法,即GC也称为分代收集算法
年轻代:存活率低,使用复制算法
老年代:区域大存活率高,使用标记清除(内存碎片不是太多)+标记压缩算法混合实现
10、JMM
Java内存模型(Java Memory Mode)
核心概念:我们的每一个线程的工作内存和主存之间存在一个抽象关系,即线程之间的共享变量存储在主内存重,每一个线程都有一个私有的本地内存。