2020年9月1日
21:29
目录 |
- - 认识JVM - 类加载器 - JVM的内存模型 - 3.1 Execution Engine - 3.2 本地方法栈,PC寄存器,方法区 - 3.3 栈 - 3.4 堆 - 堆结构 - 4. JVM参数设计 - 5. GC - 5.1 标记不可达对象 - 5.2 内存管理中垃圾回收的几种方式 - 5.3 垃圾回收算法 - 标记复制法 - 标记清除算法 - 标记压缩 - 标记清除-压缩
|
- 认识JVM
解释抽象语言为机器可识别指令序列。其基本架构如下,后续我们会详细介绍各个部分。
- 类加载器
Bootsrap负责加载jre库里的类,Extension负责加载拓展包,AppClassLoder负责加载应用程序类,包括自定义程序类。
双亲委派机制:三者继承关系如上,由父类开始加载,目的是为了避免重复加载,避免核心类被篡改(Bootstrap优先加载了核心包,无法重复加载相同实现)
- JVM的内存模型
3.1 Execution Engine
解释引擎,负责解释指令提交操作系统。
类似系统一般包含两种形式:
- 解释型,执行时逐句翻译
- 即时编译(JIT, just-in-time),编译后执行
Java中默认的引擎是HotSpot,它是默认混合策略解释执行代码,然后将其中反复执行的代码进行编译。
3.2 本地方法栈,PC寄存器,方法区
本地方法栈
保存很多调用本地操作系统的方法,接触底层硬件。初衷是在c++统治时代融合c++。
PC寄存器
每个线程都私有一个计数器。
方法区
所有线程共享的,保存静态变量,常量,类信息。
3.3 栈
栈内存生命周期跟随线程生命期,是线程私有的。
保存:基本变量,对象引用,实例方法
栈帧:每个次调用方法都会分配一个栈帧。
顺序:后进先出
3.4 堆
堆结构
堆是内存中最大的一块,是垃圾回收机制的重点工作对象。可想而知,垃圾回收与内存分配是最重要的算法。
堆在逻辑和物理上的划分是类似的。只是逻辑上,多了一块永久区(元空间,1.8之后的实现),永久区就是方法区的一种实现方式。逻辑上的划分如下:
事实上各个区的划分,其实就是一种结构化的设计——损失部分空间的代价换取简单高效的算法。为了介绍各个区的作用,先介绍整个GC机制的一种算法。其他算法将在4 GC中详细阐述。
- 一般在伊甸区创建新的对象,我们很好理解,伊甸区的大量的对象经常是短期、局部的(例如大量的方法局部变量)。
- 伊甸区满了,GC中的局部GC——minor GC就会触发,检查伊甸区,回收无引用的变量,将其余变量复制到幸存区(有from,to两部分,复制到to区)
- 与此同时,minor GC同时检查from区的对象,同样将无引用的对象复制到to区。同时,检测其中复制次数超过某个限制的(15),将其复制到养老区,这是被复制多次没有被回收,说明该对象生命长久,不应该放在from区。然后,from和to交换指针,确保to区为空(复制的时候非常高效)
- 如果养老区也爆满了,那么就会触发终极回收机制,全局GC,对所有区域进行回收
物理的划分非常类似:
4. JVM参数设计
IDEA经常配置的jvm参数就是设置上述堆和栈的参数,内存的大小当然理所应当地影响Java程序的性能。
参数名 | 含义 |
-XX:+PrintGC | 每次触发GC的时候打印相关日志 |
-XX:+PrintGCDetails | 更详细的GC日志 |
-Xms | 堆初始值(默认为物理内存的1/64) |
-Xmx | 堆最大可用值(默认为物理内存的1/4) |
-Xmn | 新生代堆初始值 |
-XX:SurvivorRatio | 用来设置新生代中eden空间和from/to空间的比例,默认为8 |
-XX:NewRatio | 配置新生代与老年代占比,默认1:2 |
-Xss | 每个线程的栈大小,默认为1M,此值不能设置过大,否则会减少线程并发数。 |
JVM中常见的异常也和堆和栈相关。例如:
java.lang.OutOfMemoryError: Java heap space ,注意到异常后面跟着的是详细位置的说明。
java.lang.StackOverflowError,栈溢出
5. GC
垃圾回收机制是JVM内存管理的核心。简单来说,GC的核心工作理念就是回收不可达对象,频繁地回收新生区,很少回收年老区,基本不动永久区。
它包含两个系统,轻量的回收机制,Minor GC,全局的回收机制,Full GC。
在上文中,我们已经介绍了Minor GC的工作原理,事实上为什么说前者是轻量的,这需要理解一下回收原理。这与操作系统的内存管理是一致的。——需要简洁高效的算法,简单,而且混合使之高效。
5.1 标记不可达对象
以前使用计数法,即在每个对象上计数,实际问题是出现交叉引用的时候,无法正常回收。例如A B对象相互引用,但二者都没有用了,没有其他外部引用,但它们的引用并不归零,所以无法正常回收。
当前使用的是可达性分析,这里并不展开,它通过分析堆外到堆内的引用来确定可达性。
5.2 内存管理中垃圾回收的几种方式
和操作系统的内存管理是一致的,JVM内存基本回收分配方法就几种——清除,压缩,复制,特点是,极其简单,各有优缺点。
清除:如图,会有碎片。
压缩:把存活的对象聚集到内存区域的起始位置,从而留下一段连续的内存空间。整理耗时。
复制:复制(copy),即把内存区域分为两等分,分别用两个指针 from 和 to 来维护,并且只是用 from 指针指向的内存区域来分配内存。复制耗时,其实和压缩有些类似。
5.3 垃圾回收算法
标记复制法
简单来说把标记的对象用于复制保留。即Minor GC使用的算法,核心是复制,缺点就是复制的对象不能太多。之所以所Minor GC轻量,就是因为该算法作用的新生区的对象生命力都很低。
标记清除算法
简单来说就是把标记的对象清除。会照成内存碎片,适用于大块区域,大量对象需要处理的情况。
标记压缩
标记的对象进行压缩。
标记清除-压缩
类似标记清除,多次之后执行压缩,也非常好理解。