加、验、准、解、初、使、卸
加、烟、准、姐、初、湿、鞋
1.1:加载、将class 文件转化为二进制流加载 JVM 内存中并生成一个该类的Class对象
1.2:验证、Class 文件的字节流中包含的信息是否符合当前虚拟机的要求
1.3:准备、在方法区中分配这些类变量所使用的内存空间
1.4:解析、虚拟机将常量池中的符号引用替换为直接引用的过程
1.5:初始化、执行类构造器
虚拟机会确保父类的
不生成client方法
强、软、弱、虚/从不/不足/GC后/跟踪回收状态
引导类加载器、扩展类加载器、应用程序类加载器
解释:自己不加载委派给父类去完成,如果无法加载则自己再加载,
好处:使用不同的类加载器最终得到的都是同样一个 Object 对象
5.1:1.7-堆、栈、方法区、程序计数器、本地方法栈
1.8-堆、栈、元空间(本地内存)、程序计数器、本地方法栈
默认堆大小:-Xms:1/64,-Xmx:1/4
新生代默认:-NewRatio:2,老年代/新生代的值= 2
新生代和幸存者区比例:8:1:1
新生代大小:-Xmn
老年代大小:堆总-新生代
|命令行|Jconsole|VisualVM|Jprofiler|Java Flight Recorder|GC Viewer|GC Easy|
6.1-引用计数法:为对象添加引用计数器,引用它+1,失效时-1
优点:实现简单,判定效率高,回收没有延时性。
缺点:需要单独的字段存储增加存储开销。
每次赋值增加时间开销。
无法处理循环引用的问题。
6.2-可达性分析法:从GC Roots到这个对象可不可达,
没有finalize()方法,直接干掉,
有的话加入队列再finalize(),有连接则移除,没有则回收。
优点:解决循环依赖问题,防止内存泄露
6.2.1-GC Roots:
6.2.1.1:各线程调用方法的参数,局部变量
6.2.1.2:本地方法栈内的引用对象
6.2.1.3:方法区中静态属性引用对象
6.2.1.4:常量引用的对象
6.2.1.5:锁持有的对象
6.2.2-finalize 方法:销毁之前自己处理逻辑,用于对象回收之前最资源的释放,只能调一次
会导致对象复活
执行时间没有保证,若不发生GC则没机会执行
严重影响性能
6.2.3-对象的三种状态:
可触及
可复活
不可触及
内存泄露:对象不可用并且垃圾收集器无法回收
内存溢出:没有足够的内存,并且垃圾收集器无法提供更多的空间
6.1-拷贝、标记清除、标记整理
6.2-分代回收思想
年轻代-拷贝,年龄+1,到15移到老年代
老年代-标记整理
6.3-分区回收思想
Region
7.1-年轻代:Serial(串)、 ParNew(并)、 Parallel Scavenge(并多、吞)-1.8默认、
7.2-老年代:Serial Old(串)、CMS(初并重并)、 Parallel Old(并)-1.8默认、
7.3-堆:G1(并发)
7.4-CMS的问题:
7.4.1-占用CPU资源而导致引用程序变慢,总吞吐量下降。默认线程数是:(CPU数量+3) / 4
7.4.2-CMS收集器无法处理浮动垃圾
7.4.3-需要预留空间供并发收集时的程序运作使用,68%时会被激活,
预留空间不够抛异常,启用Serial Old导致停顿时间过长。
7.4.4-标记清除,产生碎片。
G1:
g1在实现高吞吐量的同时,尽可能的满足垃圾收集器的暂停时间要求
内存结构:2048个Region,每个Region 大小在1-32M之间,默认年轻代初始大小整堆的5%,最大整堆的60%
PRT:Per Region Table 是RSet 在内部记录分区的引用情况。
稀少:直接记录引用对象的卡片索引
细粒度:记录引用对象的分区索引
粗粒度:只记录引用情况,每个分区对应一个比特位
SATB:
用于记录某个时间点,每个 Region 中包含的对象及其存活标记信息的快照。
写屏障:
PLAB:
线程在分配内存时,首先尝试从 PLAB 中分配。
如果 PLAB 中的空间不足,线程将开始一个新的 PLAB。
这样能够避免多个线程竞争一个全局分配缓存而导致的性能瓶颈。
1:对象的分配,修改RSet。
2:年轻代满了触发Young GC
2.1:初次标记、
2.2:在并发标记和最终标记的过程中计算出回收价值最大的Region 放入CSet
2.3: 根据CSet 进行回收,就是所谓筛选回收。如果大对象大多数已死亡也一并回收。
2.4:完成回收后,将活得对象放入幸存者区,对象年龄+1,再次修改RSet
3:有了新的空间用户线程就可以将新的对象放入Eden区了。
当Young GC 多次后,幸存者区的对象年龄超过15 将进入老年代
此时应用线程还在运行,继续产生新的对象,PLAB 用于临时存储从 Eden 区域晋升过来的对象。 在执行垃圾回收操作之前,G1 垃圾回收器会将 PLAB 中的对象依次晋升到老年代中,这样可以减少老年代中的内存分配操作,对于每个线程,G1 垃圾回收器都维护了一个或多个 PLAB。线程在分配内存时,首先尝试从 PLAB 中分配。如果 PLAB 中的空间不足,线程将开始一个新的 PLAB。这样能够避免多个线程竞争一个全局分配缓存而导致的性能瓶颈。
G1 垃圾回收器在执行 Mixed GC 之前会先记录一份 STAB,
记录 Mixed GC 区域中各个 Region 的存活对象信息和存活标记信息。
之后,G1 垃圾回收器会在 Mixed GC 区域中从存活对象开始,
检查每个已存活的对象所在的 Region,并将这些 Region 标记为 "可复制" 的备选区域。
同时,采用各种启发式算法来选择最佳的 Region 备选列表,
从而在 Mixed GC 期间减少空间碎片,提高内存利用率。
1:老年代存储达到阈值默认是45% 将触发Mixed GC
2:初次标记。
3:在并发标记和最终标记的过程中,计算出回收价值最大的Region(包含所有区的Region)放入CSet。
4: 根据CSet 进行混合回收。如果大对象少数死亡也回收一部分。
5:将存活的对象拷贝到其他的Region。
1:拷贝过程中如果发现没有足够的空region能够承载拷贝对象就会触发一次Full GC。
2:此时应用程序的执行会完全停止,进行所有区域的标记和维护操作,以获得充足的空间。
50%以上的堆被存活对象占用
对象分配和晋升的速度变化非常大
垃圾回收时间特别长,超过1秒
8GB以上的堆内存(建议值)
停顿时间是500ms以内
1:增加G1垃圾回收器的堆大小:由于G1垃圾收集器使用了分代技术,
因此需要适当增加堆大小来提高垃圾回收的效率。通常,可以通过设置
JVM 启动参数 -Xmx 和 -Xms来增加堆大小。
2:设置最大G1回收时间:在优化 G1 垃圾回收器时,需要了解每次垃圾回收所需的时间。
可以通过设置 JVM 启动参数-XX:MaxGCPauseMillis来控制最大的垃圾回收时间,
从而提高垃圾回收的效率。
3:调整G1垃圾回收器的分区大小:G1垃圾回收器将堆划分为若干个分区进行垃圾回收。
可以通过设置 JVM 启动参数 -XX:G1HeapRegionSize 来调整分区大小,
从而优化垃圾回收器的性能。
4:增加并发线程数:可以通过增加垃圾回收器的并发线程数来提高其效率。
可以使用 JVM 启动参数 -XX:ConcGCThreads 来增加并发线程数,
从而提高垃圾回收器的并发性能。
5:避免使用超大对象:G1垃圾回收器的使用应避免创建超大对象。
超大对象容易导致分配失败、GC 时间过长等问题。