决战圣地玛丽乔亚Day39 -----GC内存模型类加载
Posted Dva清流
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了决战圣地玛丽乔亚Day39 -----GC内存模型类加载相关的知识,希望对你有一定的参考价值。
内存模型:
java内存模型定义了JVM虚拟机如何与计算机的内存进行交互。java内存模型把内存划分为两部分:主内存和工作内存。主内存共享,工作内存线程私有。
java内存模型的实现有两种:基于锁的同步和volatile、 基于锁的同步和synchronized
线程私有变量可以通过ThreadLocal来创建,实现线程隔离。
内存同步性问题?涉及知识点:
Volatile、synchronized。
展开讲一讲volatile的内存屏障,总线嗅探等。
内存逃逸分析?
在编译阶段对程序进行分析,判断对象的生命周期是否逃逸出当前的方法或线程。如果没有逃逸就可以把它分配在栈或寄存器上。而不是扔在堆上
由于堆满了就要GC, 所以减轻了GC的压力。
放在栈和寄存器上,线程私有,避免锁的竞争和线程同步的问题。
GC(垃圾回收):
GC(垃圾回收)的过程:
堆的结构:
新生代:
Eden:Survivor0:Survivor1 = 8:1:1 (标记复制算法)
Eden区:新对象被创建时初始分配区
Survivor0、Survivor1:两个相同大小的区域,交替使用。
过程:
Minor GC
1.创建对象,放入Eden区,Eden区到达一个阈值的时候,触发Minor GC
第一次Minor GC:垃圾回收器标记清除不再被引用的对象,同时把Eden区和S0区的存活对象移动到S1,如果S1满了会移动到老年代。
然后S1是作为源,S0作为目标。下一次MinorGC清S1和Eden存到S0。 始终保持一个干净的Survivor区域可以用来中转存放。
Major GC(老年代清理):
1.垃圾回收器标记所有存活对象
2.垃圾回收器会遍历整个堆内存,清除所有未被标记的垃圾对象,释放这些对象占用的内存空间
3.在清除阶段结束后,堆内存中可能会出现一些内存碎片,这些碎片会影响新对象的分配和分配速度。因此,垃圾回收器通常还需要对堆内存进行整理,将所有存活对象向一端移动,从而消除内存碎片,为新对象的分配提供更大的连续空间
4.在整理阶段结束后,堆内存中会留出一些可用的连续空间,用于分配新对象。
Full GC(清理整个堆,年轻代+老年代):
老年代:
进入条件:
1.年龄满15岁,15轮minor gc -XX:MaxTurningThreshold
2.特别大的对象(大于阈值设置) -XX:PretenureSizeThreshold
3.如果幸存者区中相同年龄的所有对象大小的总和大于幸存者区空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代,无需等到MaxTenuringThreshold中要求的年龄
4.Eden区存活的对象已经超过了surcival区的大小(某一个区,超过就转不动了。)
空间分配担保(在minor gc时判断老年代是否有能力接受):
在发生minor gc之前,虚拟机必须检查
初步预判是否存的下。老年大最大可用连续空间是否大于新生代所有对象总空间
如果大于,说明一定是安全的minorgc
如果小于,看是否允许担保失败
handlepromotionfailure:是否允许担保失败的标识符,boolean类型
允许担保失败:
检查老年代最大可用连续空间是否大于历次晋升到老年代对象大小的平均值
大于:尝试一次minor gc
小于:直接full gc
不允许担保失败:直接fullgc
常见的垃圾回收器:
Serial垃圾回收器:单线程,垃圾收集的时候会stop the world暂停所有应用程序,只留一个线程进行垃圾回收操作。
Parallel垃圾回收器:
优:多线程的垃圾回收器,它可以使用多个线程并行执行垃圾回收操作,从而提高垃圾回收的效率。
缺:在执行垃圾回收操作时需要暂停所有的应用程序线程,可能会导致较长的停顿时间。
CMS(最短回收停顿时间):
多线程标记清除收集器,标记清除的过程:
1.初始标记:暂停所有的应用程序线程,标记所有根对象以及直接与根对象相关联的对象,将它们的标记位设置为已标记状态,并建立标记工作列表。
2.并发标记:并发地标记所有已经被引用的对象,即从标记工作列表中取出一个对象并标记它所引用的其他对象,将它们的标记位设置为已标记状态,并将它们加入标记工作列表中。
3.重新标记:为了保证标记的准确性,需要在应用程序线程运行的同时重新标记所有被修改的对象和被遗漏的对象,确保所有被引用的对象都被正确标记。
4.并发清除:并发地清除所有未被标记的对象,即将它们所占用的内存空间标记为空闲状态,并将它们加入空闲列表中,以备后续的分配使用。
在CMS的垃圾回收过程中,需要控制最短回收停顿时间,一般通过以下两种方式来实现:
1.预留内存空间:为了避免由于频繁的垃圾回收操作导致堆内存不足而导致的停顿,CMS在运行时会预留一部分内存空间,用于存放垃圾对象。当堆内存快要达到预留空间的上限时,CMS会触发垃圾回收操作,从而避免因为内存不足而导致的停顿。
2.并发执行:CMS是一种并发的垃圾回收器,它可以在应用程序运行的同时执行垃圾回收操作。在标记和清除阶段,CMS只会暂停应用程序线程的执行,而不会暂停整个应用程序,从而减少了停顿的时间。
优点:可以在应用程序运行的同时执行垃圾回收操作,减少应用程序的停顿时间,适合对应用程序响应速度有较高要求的场景。
缺点:可能会导致堆内存碎片化,需要额外的内存来维护垃圾回收操作。
G1(年轻代、老年代 可预测时间停顿):
初始标记(Initial Mark):暂停所有的应用程序线程,标记所有根对象以及直接与根对象相关联的对象,并建立标记工作列表。
并发标记(Concurrent Mark):并发地标记所有已经被引用的对象,即从标记工作列表中取出一个对象并标记它所引用的其他对象,将它们的标记位设置为已标记状态,并将它们加入标记工作列表中。
最终标记(Final Mark):在应用程序线程运行的同时重新标记所有被修改的对象和被遗漏的对象,确保所有被引用的对象都被正确标记。
筛选回收(Live Data Counting and Evacuation):
把内存分为很多区域region,不再坚持固定大小和固定分代。
1.计算每个区域的回收价值,即空闲区域的大小和存活数量。存活少空闲多的回收价值就高。
2.根据回收价值从高到低排序,把存活对象复制到其他区域,清除这些回收价值高的区域变为空白。
举个例子来说明,假设G1将堆内存分成了10个大小相等的区域,其中第1个区域是Eden区,第2和第3个区域是Survivor区,剩下的7个区域是Old区。在筛选回收过程中,假设第4个区域中存活对象的数量最少、空闲内存最多,因此它的回收价值最高,G1会将这个区域的存活对象复制到其他空闲区域,并清空这个区域,以备后续的分配使用。
可预测时间停顿是指G1在垃圾回收过程中会将整个堆内存分成多个区域,每个区域的大小和回收效率都不同,通过预测每个区域的回收时间,G1可以控制垃圾回收的时间,并尽可能保持停顿时间的稳定性,从而避免因为频繁的垃圾回收操作而导致的不可预测的停顿时间。 G1垃圾回收器的优点是可以在堆内存非常大的情况下保证可预测的停顿时间,同时可以避免Full GC导致的长时间停顿,提高了应用程序的性能和可靠性。
优点:将堆内存分成多个小块,可以提高垃圾回收的效率和可控性,适合大型应用程序和服务端应用程序。
缺点:在执行垃圾回收操作时需要消耗额外的CPU和内存资源,不适合小型应用程序。
并发标记为什么会存在漏标的情况?
并发修改:由于并发执行的应用程序可能会修改一些对象的引用关系,例如将一个原本指向一个存活对象的引用修改为指向一个已经被回收的对象,或者反过来。如果这些修改发生在并发标记的过程中,那么标记器可能无法及时地发现这些变化,并及时更新对象的标记位。
RSet漏标:在使用SATB技术时,如果应用程序在并发执行的过程中不断地修改对象的引用关系,那么可能会导致一些引用关系没有被及时地添加到RSet中,从而出现了RSet漏标的情况。如果这些漏标的引用关系指向的是存活对象,那么这些存活对象就有可能被错误地回收。 为了解决这些问题,G1垃圾回收器采用了一系列的技术手段,例如增量更新RSet、卡表技术等,来减少漏标的发生,从而提高回收器的准确性和效率。
在并发标记的过程中可能会存在漏标,G1垃圾回收器通过STAB可以进行处理:
G1垃圾回收器引入了一种叫做“SATB”(Snapshot-At-The-Beginning)的技术,即在并发标记的开始时,生成一个快照,记录下当前所有的引用关系,然后在标记过程中,如果遇到一个对象被修改了(即它所指向的对象发生了变化),就将这个对象的引用添加到一个叫做“RSet”(Remembered Set)的集合中。在最终标记阶段,G1会遍历所有的RSet,将其中的引用关系加入到标记工作列表中,并进行标记。这样就可以避免因为漏标而导致的存活对象被错误地回收的问题。
CMS和G1的选择:
大量短时间存活对象的应用程序G1,因为这些对象会被根据回收价值尽快回收,不会占用过多的内存空间。
大量长时间存活对象的应用程序用CMS,因为这些对象会被标记为“存活”,不会被过早回收。标记清除算法。
最新的ZGC有什么改良?
大内存管理:ZGC可以管理非常大的内存,最大可达到4TB。
低延迟:ZGC可以实现非常低的停顿时间,最多只有10毫秒,不会对应用程序的性能产生明显影响。
并发性:ZGC是一种并发的垃圾回收器,可以在应用程序运行的同时执行垃圾回收操作,减少应用程序的停顿时间。
无需设定堆大小:ZGC无需事先设定堆的大小,它可以自动调整堆的大小以适应应用程序的内存需求。
无需分代:ZGC不需要分代,它可以同时管理新生代和老年代,减少了内存管理的复杂度。
跨平台:ZGC可以在不同操作系统和硬件平台上运行,具有很好的跨平台性和可移植性。
类加载机制:
JIT:
常见问题排查:
以上是关于决战圣地玛丽乔亚Day39 -----GC内存模型类加载的主要内容,如果未能解决你的问题,请参考以下文章
决战圣地玛丽乔亚Day53-----分布式原理与RPC之服务治理与基本原理
Flutter 做一个类似超级玛丽 (想不起来名字 挺好玩反正)Flutter写个小游戏,欢迎一起撸代码 185行 代码逆天改命