一. 类的加载机制
- 过程
- 将.class的二进制数据读入内存,放入方法区中
- 在堆中创建一个java.lang.Class对象,封装类在方法区中的数据结构,并提供访问方法区数据结构的接口
- 类的生命周期
- 类的加载过程
- 加载:查找并加载类的二进制数据,在堆中创建java.lang.Class类对象
- 连接
- 验证:文件格式,元数据,字节码,符号引用验证
- 准备:为类的静态变量分配内存,并将其初始化为默认值
- 解析:把类中的符号引用转换为直接引用
- 初始化:为类的静态变量赋正确的初始值
- 使用:new出对象,程序中使用
- 卸载:执行垃圾回收
- 图示:
- 类的加载过程
- 类加载器:
- 分类:
- 启动类加载器:加载JDK\jre\lib下或者被-Xbootclasspath指定的路径下的类库
- 扩展类加载器:加载JDK\jre\lib\ext下或者被java.ext.dirs指定的类库(javax.*开头)
- 应用程序类加载器:加载用户类路径所指定的类(ClassPath)
- 父子关系
- 分类:
- 类加载机制
- 全盘负责:当一个类加载器加载某个类,则这个类引用的其他class也有该类加载器负责载入
- 父类委托:先让父类加载器加载,如果不能加载,在从自己的类路径加载
- 缓存机制:所有加载过得类都会被缓存,然后当需要使用某个class时,先看缓存区中是否存在(所以改完class需要重启JVM)
二. jvm内存结构
- 组成:
- Java堆:存放对象实例,所有线程共享
- 组成
- 年轻代(括号中是内存比例)
- Eden(8)
- From Survivor(1)
- To Survivor(1)
- 老年代
- 年轻代(括号中是内存比例)
- 控制参数
- -Xms设置堆的最小空间大小。
- -Xmx设置堆的最大空间大小。
- -XX:NewSize设置新生代最小空间大小。
- -XX:MaxNewSize设置新生代最大空间大小。
- -XX:PermSize设置永久代最小空间大小。
- -XX:MaxPermSize设置永久代最大空间大小。
- -Xss设置每个线程的堆栈大小。
- 组成
- 方法区:存放虚拟机已经加载的类,常量,静态变量,即时编译器编译的代码,所有线程共享
- 程序计数器:当前线程执行的字节码的行号指示器,线程私有
- JVM栈:声明周期和线程相同,每个方法调用到执行,对应栈帧在JVM栈中入栈出栈
- 本地方法栈:与JVM栈相似,虚拟机用到的Native方法的入栈出栈
- Java堆:存放对象实例,所有线程共享
- 内存结构图示:
- 对象分配规则
- 对象优先分配Eden区:如果Eden区没有足够空间,执行一次Minor GC
- 大对象(需要大量连续内存空间的对象)直接进入老年代:为了避免在Eden和Survivor发生大量数据拷贝(年轻代使用复制算法收集内存)
- 长期存活的对象进入老年代:长期存活的判定是,有一个年龄计数器,对象经过一次MinorGc,进入Surviror,之后每经过一次MinorGC,则年龄加1,到达一定值,进入老年区
- 动态判断对象的年龄:如果Survivor区中相同年龄的所有对象,大小总和大于Survivor的一半,则大于等于该年龄的对象可以直接进入老年代
- 空间分配担保:每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC,如果小于检查HandlePromotionFailure设置,如果true则只进行Monitor GC,如果false则进行Full GC。
三. GC算法
- 对象存活判断
- 两种方式:
- 引用计数:有一个引用的时候这个对象的引用计数属性加1,引用释放之后,计数减1,为0表示可回收
- 可达性分析:从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,不可达对象。
- GC Roots包括:
- 虚拟机栈中引用的对象。
- 方法区中类静态属性实体引用的对象。
- 方法区中常量引用的对象。
- 本地方法栈中JNI引用的对象。
- GC Roots包括:
- 两种方式:
- GC算法
- 基础算法
- 标记 -清除算法:算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。
- 复制算法:将可用内存分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
- 标记-压缩算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
- 分代收集算法(垃圾回收器使用):
- 年轻代:复制算法
- 老年代:标记-清除和标记-压缩
- 基础算法
- 垃圾回收器及组合策略表格
垃圾回收器 |
年轻代 |
老年代 |
参数控制 |
目标 |
Serial收集器 |
串行,复制 |
串行,标记-压缩 |
-XX:+UseSerialGC 串行收集器 |
|
ParNew收集器 |
并行,复制 |
串行,标记-压缩 |
-XX:+UseParNewGC ParNew收集器 -XX:ParallelGCThreads 限制线程数量 |
|
Parallel收集器 |
自适应,复制 |
串行,标记-压缩 |
-XX:+UseParallelGC 使用Parallel收集器+ 老年代串行 |
最合适的停顿时间 最大的吞吐量 |
Parallel Old 收集器 |
自适应,复制 |
并行,标记-压缩 |
-XX:+UseParallelOldGC 使用Parallel收集器+ 老年代并行 |
最合适的停顿时间 最大的吞吐量 |
CMS收集器 |
ParNew收集器 |
并行,标记-清除 |
-XX:+UseConcMarkSweepGC 使用CMS收集器 -XX:+ UseCMSCompactAtFullCollection Full GC后,进行一次碎片整理;整理过程是独占的,会引起停顿时间变长 -XX:+CMSFullGCsBeforeCompaction 设置进行几次Full GC后,进行一次碎片整理 -XX:ParallelCMSThreads 设定CMS的线程数量(一般情况约等于可用CPU数量) |
获取最短回收停顿时间 优点:并发收集,低停顿 缺点:产生大量碎片,并发阶段会降低吞吐量 |
G1收集器 |
并行,标记-压缩 |
并行,标记-压缩 |
-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC 开启 -XX:MaxGCPauseMillis =50 暂停时间目标 -XX:GCPauseIntervalMillis =200 暂停间隔目标 -XX:+G1YoungGenSize=512m 年轻代大小 -XX:SurvivorRatio=6 幸存区比例 |
常用组合 |
新生代GC策略 |
年老代GC策略 |
说明 |
组合1 |
Serial |
Serial Old |
Serial和Serial Old都是单线程进行GC,特点就是GC时暂停所有应用线程。 |
组合2 |
Serial |
CMS+Serial Old |
CMS(Concurrent Mark Sweep)是并发GC,实现GC线程和应用线程并发工作,不需要暂停所有应用线程。另外,当CMS进行GC失败时,会自动使用Serial Old策略进行GC。 |
组合3 |
ParNew |
CMS |
使用-XX:+UseParNewGC选项来开启。ParNew是Serial的并行版本,可以指定GC线程数,默认GC线程数为CPU的数量。可以使用-XX:ParallelGCThreads选项指定GC的线程数。 如果指定了选项-XX:+UseConcMarkSweepGC选项,则新生代默认使用ParNew GC策略。 |
组合4 |
ParNew |
Serial Old |
使用-XX:+UseParNewGC选项来开启。新生代使用ParNew GC策略,年老代默认使用Serial Old GC策略。 |
组合5 |
Parallel Scavenge |
Serial Old |
Parallel Scavenge策略主要是关注一个可控的吞吐量:应用程序运行时间 / (应用程序运行时间 + GC时间),可见这会使得CPU的利用率尽可能的高,适用于后台持久运行的应用程序,而不适用于交互较多的应用程序。 |
组合6 |
Parallel Scavenge |
Parallel Old |
Parallel Old是Serial Old的并行版本 |
组合7 |
G1GC |
G1GC |
-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC #开启 -XX:MaxGCPauseMillis =50 #暂停时间目标 -XX:GCPauseIntervalMillis =200 #暂停间隔目标 -XX:+G1YoungGenSize=512m #年轻代大小 -XX:SurvivorRatio=6 #幸存区比例 |