JAVA面试_进阶部分_Java JVM:垃圾回收(GC 在什么时候,对什么东西,做了什么事情)

embedded/2025/3/14 8:09:05/

在什么时候:

首先需要知道,GC又分为minor GC 和 Full GC(major GC)。Java堆内存分为新生代和老年代,新生代

中又分为1个eden区和两个Survior区域。

一般情况下,新创建的对象都会被分配到eden区,这些对象经过一个minor gc后仍然存活将会被移动到

Survior区域中,对象在Survior中没熬过一个Minor GC,年龄就会增加一岁,当他的年龄到达一定程度时,

就会被移动到老年代中。

当eden区满时,还存活的对象将被复制到survior区,当一个survior区满时,此区域的存活对象将被复制到另外一个

survior区,当另外一个也满了的时候,从前一个Survior区复制过来的并且此时还存活的对象,将可能被复制到老年代

因为年轻代中的对象基本都是朝生夕死(80%以上),所以年轻代的垃圾回收算法使用的是复制算法,

复制算法的基本思想是将内存分为两块,每次只有其中一块,当这一块内存使用完,就将还活着的对象复制到

另一块上面。复制算法不会产生内存碎片。

在GC开始的时候,对象只会存在于eden区,和名为“From”的Survior区,Survior区“to”是空的。紧接着GC

eden区中所有存活的对象都会被复制到“To”,而在from区中,仍存活的对象会根据他们的年龄值来决定去向,

年龄到达一定只的对象会被复制到老年代,没有到达的对象会被复制到to survior中,经过这次gc后,eden区和from

survior区已经被清空。这个时候,from和to会交换他们的角色,也就是新的to就是上次GC前的from

Minor GC:从年轻代回收内存

jvm无法为一个新的对象分配空间时会触发Minor GC,比如当Eden区满了。

当内存池被填满的时候,其中的内容全部会被复制,指针会从0开始跟踪空闲内存。Eden和Survior区不存在内存碎片

写指针总是停留在所使用内存池的顶部。执行minor操作时不会影响到永久代,从永久带到年轻代的引用被当成

GC roots,从年轻代到永久代的引用在标记阶段被直接忽略掉(永久代用来存放java的类信息)。如果eden区域中大部分

对象被认为是垃圾,永远也不会复制到Survior区域或者老年代空间。如果正好相反,eden区域大部分新生对象不符合GC

条件,Minor GC执行时暂停的线程时间将会长很多。Minor may call “stop the world”;

Full GC:是清理整个堆空间包括年轻代和老年代。

那么对于Minor GC的触发条件:大多数情况下,直接在eden区中进行分配。如果eden区域没有足够的空间,

那么就会发起一次Minor GC;对于FullGC的触发条件:如果老年代没有足够的空间,那么就会进行一次FullGC

在发生MinorGC之前,虚拟机会先检查老年代最大可利用的连续空间是否大于新生代所有对象的总空间。

如果大于则进行Minor GC,如果小于则看HandlePromotionFailure设置是否是允许担保失败(不允许则直接FullGC)

如果允许,那么会继续检查老年代最大可利用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于

则尝试minor gc (如果尝试失败也会触发Full GC),如果小于则进行Full GC。

但是,具体什么时候执行,这个是由系统来进行决定的,是无法预测的。

对什么东西:

主要根据可达性分析算法,如果一个对象不可达,那么就是可以回收的,如果一个对象可达,那么这个对象就不可以回收,

对于可达性分析算法,它是通过一系列称为“GC Roots”的对象最为起始点,当一个对象GC Roots没有任何引用链相接的时候,

那么这个对象就是不可达,就可以被回收。

做了什么事情:

主要做了清理对象,整理内存的工作。Java堆分为新生代和老年代,采用了不同的回收方式。

例如新生代采用了复制算法,老年代采用了标记整理法。在新生代中,分为一个ede区域和两个Survior

区域,真正使用的是一个eden区域,和一个Survior区域,GC的时候,会把存活的对象放入到另一个Survior区域中,

然后再把这个eden区域和Survior区域清除。那么对于老年代,采用的是标记整理发,首先标记出存活对象,

然后在移动到一段。这样有利于减少内存碎片。

标记:标记的过程其实就是,遍历所有gc root 然后将所有gc root 可达的对象标记为存活对象

清除:清除的过程中将遍历堆中所有的对象,将没有标记的对象全部清除掉

主要缺点:标记和清除过程效率不高,标记清除之后会产生大量不连续的内存碎片

但是,老年代中因为对象存活率高,没有额外空间对他进行分配担保,就必须使用标记整理算法

标记整理算法 标记操作和“标记-清除”算法一致,后续操作不只是直接清理对象,而是在清理

无用对象完成后让所有存活的对象都向一段移动,并更新其引用对象的指针

主要缺点:在标记清除的基础上还需要进行对象的移动,成本相对比较高,成本相对较高,好处是不会产生内存碎片。


http://www.ppmy.cn/embedded/172446.html

相关文章

【算法day9】字符串转换整数 (atoi);请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数。

字符串转换整数 (atoi) https://leetcode.cn/problems/string-to-integer-atoi/description/ 请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数。 函数 myAtoi(string s) 的算法如下: 空格:读入字符串并丢…

FiddlerScript学习笔记

参考官方文档:https://www.fiddlerbook.com/fiddler/dev/scriptsamples.asp json // 反序列化 static function jsonDecode(str : String){return Fiddler.WebFormats.JSON.JsonDecode(str).JSONObject; } // 序列化 static function jsonEncode(jsonObject : Obje…

Doris 数据划分:分区与分桶策略全解析

在 Doris 的分布式架构里,数据划分策略是实现高效存储和查询的关键所在。它主要依靠分区(Partition)和分桶(Bucket)这两层逻辑划分,对数据的分布进行精细化管理。本文将深入探讨这两种策略的设计思路、实际…

4-002:如何使用 MySQL 的 EXPLAIN 语句进行查询分析?

EXPLAIN 是 MySQL 中用于分析查询性能的工具,能够帮助你理解查询的执行计划。通过 EXPLAIN,你可以查看 MySQL 如何执行查询,包括使用的索引、表连接顺序等信息。 基本用法 在查询前加上 EXPLAIN 即可: EXPLAIN SELECT * FROM y…

在 Linux 64 位系统上安装 Oracle 11g R2 数据库的完整指南

linux.x64_11gR2_database 是 Oracle 数据库 11g 第 2 版(11g Release 2)的安装包,适用于 64 位 Linux 操作系统。这个安装包包含了在 64 位 Linux 系统上安装 Oracle 数据库所需的全部文件和组件。 安装步骤概述 以下是在 Linux 系统上安装…

c语言闯算法--常用技巧

双指针 类别&#xff1a; 同向快慢指针 异常情况&#xff0c;慢指针才动 双向指针 视情况&#xff0c;左右指针动 最长无重复子串 int max(int a, int b){if(a < b){return b;}else{return a;} } int lengthOfLongestSubstring(char* s) {int count[300];for(int i 0; i …

红帆 iOffice M2 移动端密码爆破的渗透测试思路,绕过客户端实现Burpsuite批量跑,分享渗透思路,共建网络安全

一、本文概述 今天来自于领导的一个需求,需要对甲方的红帆 ioffice M2进行一次渗透测试【有授权书的】,拿到对应的APP和接口以后,我发现了进行不下去的一个关键点,他家的OA只有APP端,没有Web端,而且密码被加密了。 二、开始分析 红帆 iOffice M2,在登录的过程中,涉及…

自定义日志回调函数实现第三方库日志集成:从理论到实战

一、应用场景与痛点分析 在开发过程中&#xff0c;我们经常会遇到以下场景&#xff1a; 日志格式统一&#xff1a;第三方库使用自己的日志格式&#xff0c;导致系统日志混杂&#xff0c;难以统一管理和分析。日志分级过滤&#xff1a;需要动态调整第三方库的日志输出级别&…