如何确定那些对象应该进行回收
垃圾回收是老生常谈的问题,那什么对象应该回收,以及如何确认为垃圾
在java中使用的是**根可达性算法
**
什么是根可达性算法
从一组称为"根节点"(Roots)的引用出发,通过追踪引用链,确定哪些对象是可达的(有引用指向的),哪些对象是不可达的(没有引用指向的)。不可达的对象被标记为垃圾,并最终被回收。
上面写的貌似很难理解,没办法,官话要是一下就被理解了,那怎么能体现出高大尚呢?
不要紧,上图
怎么清除垃圾对象
先来回顾一下堆空间结构,堆空间被分为新生代和老年代,不同的代使用不同的回收算法
新生代使用的是复制算法
老年代使用的是标记整理算法
复制算法
复制算法的两个主要阶段:标记阶段和复制阶段
标记阶段: 这个阶段的目标是标记所有从根对象直接或间接可达的存活对象。垃圾回收器从根对象(如线程栈中的引用、静态变量等)出发,通过追踪对象引用关系,标记所有可达的对象。
复制阶段: 在标记阶段完成后,接下来是复制阶段。在这个阶段,只有被标记为存活的对象会被复制到另一个存活区域(通常是一个Survivor区)。这个过程实际上是将存活对象从一个区域复制到另一个区域,同时清理掉原始区域中的非存活对象。由于复制的过程,原始区域可以一次性清空,而不需要考虑内存碎片的问题。
优点:
简单高效: 实现简单,不需要考虑内存碎片问题,只需要两块Survivor区和一块Eden区即可。
快速分配内存: 由于只需要将存活对象复制到Survivor区,Eden区的清理过程非常迅速。
缺点:
内存利用率较低: 复制算法需要额外的内存空间,年轻代的内存利用率相对较低。
对象晋升: 存活较久的对象会被晋升到年老代,增加了年老代的负担。
了解完基本知识后,通过一张图来加深体验
标记-整理算法
标记阶段: 从根对象开始,通过可达性分析算法遍历整个对象图,标记所有可达的存活对象
清理阶段: 清理掉不再被引用的对象,释放内存空间,确保老年代只包含存活对象。
整理阶段(可选): 优化内存布局,将存活对象紧凑排列在一起,减少内存碎片。在清理阶段后,可能会产生内存碎片,即一些被回收的对象在老年代中留下的不连续的内存空间。
优点: 内存利用高、整理过程可选
缺点: 停顿时间较长、内存拷贝开销、复杂性
此处还是一样,继续上图加深体验
JVM相关知识普及
内存溢出
年轻代垃圾回收(YGC): 伊甸区区满了
老年代垃圾回收(OGC): 老年代内存区域满了
全局垃圾回收(FullGC): 整个堆空间回收,例如:老年代多次回收之后,没有释放空间,新生代持续产生对象
STW(Stop-the-World )
采访一下小伙伴们,有没有面试遇到过STW
相关的问题呢?
什么是STW
STW
是指在程序执行时,垃圾回收器会暂停所有应用线程的执行,以执行一些与垃圾回收相关的任务
Tip:
在日常开发中,小伙伴们处理问题,有没有遇到系统突然一段时间没办法正常执行,需要等待一会自己就会恢复,然后运行一会又会重复之前的问题,这种现象就可能是GC时间太长,从而导致长时间的STW,当然有问题就会有处理办法,后续会输出相关文章
STW的存在为了解决以下几个问题
一致性和安全性: java程序在运行时,会不断的产生新对象,如果不停顿应用程序,可能会导致垃圾回收器无法正确地识别对象的引用关系。
简化实现: STW 简化了垃圾回收器的实现,因为在没有并发干扰的情况下,垃圾回收器可以更容易地操作内存。好比我们处理线程并发问题时,上锁是一个道理
话题到这就结束了,JVM涉及到的东西太多了,只能介绍一些工作中会遇到的概念,以上仅仅是个人理解,如有不对,欢迎小伙伴评论指正