JAVA面试2——GC垃圾回收机制

本文详细解析了Java垃圾回收机制,包括新生代与老年代的回收策略,如复制、标记-清除及标记-整理算法。介绍了GCROOTS概念及CMS、G1垃圾回收器的工作原理,探讨了对象创建过程及内存分配策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

垃圾回收机制 Garbage Collection
1.垃圾回收机制主要是对堆进行的,
而且是分类进行的,分为新生代和老年代
新生代的回收主要以复制为形式,年轻代的比较容易被当成垃圾删除,将整个年轻代分为8:1:1,8是Eden区,另外两个servive区。没有被标记出来要删除的存放在E+S0去到S1,新的对象放在E里面,下一轮在E+S1放在E0里面,依此循环,年轻代经历了6代还没有被取代的时候,就进入老年代;
老年代的回收主要以标记-清除和标记-整理为主,前者会产生内存碎片,后者会很消耗内存。
在这里插入图片描述

2.那什么样的垃圾会被标记为垃圾呢?就是没有被引用到的那个堆里的对象,jvm栈会去指向堆里面的对象,同时堆里面的对象可能回去指向堆里面另外一些对象,那些完全没有被引用的就是垃圾
有的地方使用的是引用次数计数,比如python,但这样的话循环引用的情况就会被忽略,因此JVM里面采用了一种叫GC ROOTS的方法
一切被GC ROOTS直接或间接引用的都会被排除,
而ROOTS包含哪一些呢?

3.垃圾回收器
也是分为老年代和年轻代的
年轻代的有Serial,对应的老年代的Serial Old
这两个是单线程的,STW(Stop-the-World)的
随后有出现了PS和PO,是多线程但还是STW的
再后来又出现了CMS给老年代的,出现了专门为CMS准备的为年轻代做准备的parNew
在这里插入图片描述
在这里插入图片描述

4.CMS是咋样的呢?
CMS的诞生是为了增加效率,提高并发率的,在原来的多线程的基础上,首先在程序正常运行之前做STW,目的是做根的初始标记,这个时间不会花很久,随后在程序运行期间并发的对其他内容进行标记,完事儿之后,由于是并发的,会导致有一些被记做事垃圾的内容重新被指向,也会导致一些漏记;因此随后还会进行一次重新标记(这个有可能很长时间,是一个BUG),采用的是三色标记算法。然后又并发的进行清理,产生的浮动垃圾下一次就会收集。
在这里插入图片描述

5.三色标记算法
自己被遍历过,子对象被遍历过就是黑
自己被遍历过,子对象没有被遍历过就是灰
没有被遍历过就是白,
浮动垃圾无所谓,但如果灰的断开了,黑的去连接了,白的是不会被找到的,就会被当成垃圾,但实际上不是垃圾;
如果黑的连上一个新的,就变成灰
但是会有一个线程的问题,如果同一个黑的,先是连上一个新的,然后变成灰的,另外一边又来一个判断他应该是黑了,于是就不回收了

5.G1
现在JDK1.8一般都是用G1的,就不是分代模型了
G1采用了一个分块的模式,把堆内存分为一个一个的块儿
当有需要的时候再进行分配,一共有ESO三种
内存的大小可以设置为1M-32M,也可以相邻的O一起使用
复制的算法就是和原来一样,随机选择一个灰色的块儿作为S1区

Old区的对象是采用Mix GC的,先是初次标记,标记Root Region
然后把Root Region的内容扫描整个Old区的所有region是不是有Rset区包含Root Region的,然后标识起来;
然后进行并发标记,只查看第二步中标记出来的region
然后重新标记,标记使用一个比CMS效率高的三色算法
复制清理,只选择了垃圾较多的region进行清理

Rset——RememberSet,记录其他对象引用自己
Cset——ClearSet,记录本次需要清除的垃圾

6.对象创建的过程
在这里插入图片描述
两种方式:指针碰撞和空闲列表。我们具体使用的哪一种,就要看我们虚拟机中使用的是什么垃圾回收机制了,如果有压缩整理,可以使用指针碰撞的分配方式。
指针碰撞:假设Java堆中内存是绝对规整的,所有用过的内存度放一边,空闲的内存放另一边,中间放着一个指针作为分界点的指示器,所分配内存就仅仅是把哪个指针向空闲空间那边挪动一段与对象大小相等的举例,这种分配方案就叫指针碰撞
空闲列表:有一个列表,其中记录中哪些内存块有用,在分配的时候从列表中找到一块足够大的空间划分给对象实例,然后更新列表中的记录,这就叫做空闲列表。

线程安全性问题
在两个线程同时创建对象时,可能会造成空间分配的冲突,解决方案有:线程同步(但执行效率过低)或给每一个线程单独分配一个堆区域TLAB Thread Local Allocation Buffer(本地线程分配缓冲)。
在这里插入图片描述
对象的访问定位有两种方式:句柄访问和直接指针

### 垃圾回收机制GC面试常见问题与解答 #### 什么是垃圾回收? 垃圾回收是指程序运行过程中自动管理内存的技术,通过识别不再使用的对象并释放其占用的内存资源。这有助于防止内存泄漏和其他由手动内存管理引起的错误[^2]。 #### Python 和 Java垃圾回收有何不同之处? Python 主要依赖于引用计数作为基本的垃圾收集方法,并辅以周期性的分代回收来处理循环引用等问题;而 Java 则广泛运用可达性分析来进行垃圾检测,这种方法能更有效地应对复杂的数据结构和多线程场景中的内存管理挑战[^4]。 #### 如何理解 Python 中的分代回收算法? 在 Python 中,新创建的对象被放置到年轻一代中,随着这些对象经历多次垃圾回收过程而不被销毁,则会被移动至年老一代。对于较新的对象,由于它们更容易成为垃圾的可能性较大,因此会更加频繁地对其进行扫描清理;而对于那些长期存活下来的对象来说,检查频率相对较低一些。这种做法提高了整体效率,减少了不必要的性能开销。 ```python import gc def create_cycle(): a = [] b = {} a.append(b) b['a'] = a create_cycle() gc.collect() # 手动触发一次完整的垃圾回收流程 ``` #### 开发者为什么需要了解 GC 工作原理? 尽管现代编程语言提供了自动化工具帮助我们更好地控制应用程序内的资源分配情况,但对于某些特定应用领域而言——比如高性能计算或嵌入式系统开发——深入理解底层运作细节仍然至关重要。掌握有关如何调整 JVM 参数的知识可以帮助开发者优化程序表现,在面对复杂的业务逻辑时做出更为合理的架构决策[^3]。 #### Java 内存模型 (JMM) 是什么? Java 内存模型定义了一套规则用于描述多个线程之间是如何相互作用访问共享数据的行为模式。它确保了即使是在并发执行的情况下也能保持一致性状态更新操作的结果正确无误。具体来讲,JMM 规定了哪些读写动作可以重排序、可见性保障措施等内容[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值