当前位置: 首页 > news >正文

java面试-GC垃圾回收机制

原理:

GC是垃圾收集的意思(Garbage Collection),Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的。

简而言之,GC是将java的无用的堆对象进行清理,释放内存,以免发生内存泄露。

问题一:为什么需要垃圾回收?

答:如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收。除非内存无限大,我们可以任性的分配而不回收,但是事实并非如此。所以,垃圾回收是必须的。

问题二:常见的垃圾回收算法有哪些?

答:

1、标记-清除算法 (老年代GC采用的算法)

分为两个阶段:标记阶段清除阶段

标记阶段:首先标记出所有需要回收的对象。

清除阶段:统一回收所有被标记的对象。

缺点:标记和清除过程效率都不高会产生大量不连续的内存碎片,导致无法给大对象分配内存。 

这种算法的不足主要体现在效率和空间,从效率的角度讲,标记和清除两个过程的效率都不高;从空间的角度讲,标记清除后会产生大量不连续的内存碎片, 内存碎片太多可能会导致以后程序运行过程中在需要分配较大对象时,无法找到足够的连续内存而不得不提前触发一次垃圾收集动作。

2、复制算法 (新生代GC采用的算法)

分为两个阶段:标记阶段复制阶段

标记阶段:首先需要先标记出存活的对象。

复制阶段:把存活的对象都复制到一块新的空内存里去,最后将原来的内存空间清空。

复制算法是为了解决效率问题而出现的,它将可用的内存分为两块,每次只用其中一块,当这一块内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已经使用过的内存空间一次性清理掉

缺点:内存缩小为了原来的一半,在对象存活率较高的场景下要进行大量的复制操作,效率很低。

 

3、标记-整理算法

分为三个阶段:标记阶段整理阶段清除阶段

标记阶段:首先需要先标记出存活的对象。

整理阶段:将所有的存活对象压缩到内存的一端。

清除阶段:把存活边界外的内存空间都清除一遍。

4、分代收集算法:

存活率低:少量对象存活,适合复制算法:在新生代中,每次GC时都发现有大批对象死去,只有少量存活(新生代中98%的对象都是“朝生夕死”),那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成GC。

存活率高:大量对象存活,适合用标记-清理标记-整理算法:在老年代中,因为对象存活率高、没有额外空间对他进行分配担保,就必须使用“标记-清理”/“标记-整理”算法进行GC。

 现代商用虚拟机基本都采用分代收集算法来进行垃圾回收。这种算法没什么特别的,无非是上面内容的结合罢了,根据对象的生命周期的不同将内存划分为几块,然后根据各块的特点采用最适当的收集算法。大批对象死去、少量对象存活的(新生代),使用复制算法,复制成本低;对象存活率高、没有额外空间进行分配担保的(老年代),采用标记-清理算法或者标记-整理算法

问题三:介绍一下新生代、老年代、永久代和各种GC

答: 

JVM 中的堆,一般分为三大部分:新生代、老年代、永久代

1. 新生代

主要是用来存放新生的对象,新生代通常存活时间较短。一般占据堆的 1/3 空间。由于频繁创建对象,所以新生代会频繁触发 MinorGC(也叫新生代GC) 进行垃圾回收。

MinorGC:采用复制算法。(问题二有介绍复制算法)

新生代分为 Eden 区ServivorFromServivorTo 三个区。

  • Eden 区:Java 新对象的出生地(如果新创建的对象占用内存很大,则直接分配到老年代)。当 Eden 区内存不够的时候就会触发 MinorGC,对新生代区进行一次垃圾回收。
  • ServivorTo:保留了一次 MinorGC 过程中的幸存者。
  • ServivorFrom:上一次 GC 的幸存者,作为这一次 GC 的被扫描者。

当 JVM 无法为新建对象分配内存空间的时候 (Eden 满了),Minor GC 被触发。因此新生代空间占用率越高,Minor GC 越频繁。

可以看出触发新生代GC的条件是Eden 满了

2. 老年代

老年代的对象比较稳定,对象存活的时间比较长。所以 MajorGC 不会频繁执行。在进行 MajorGC(也叫老年代GC) 前一般都先进行了一次 MinorGC新生代GC),使得有新生代的对象晋身入老年代,导致空间不够用时才触发。当无法找到足够大的连续空间分配给新创建的较大对象时也会提前触发一次 MajorGC 进行垃圾回收腾出空间。

MajorGC: 采用标记—清除算法 (问题二有介绍标记—清除算法)  * 有的地方等同于Full GC,有的地方单单指老年代的GC。

3. 永久代

指内存的永久保存区域,主要存放 Class 和 Meta(元数据)的信息

Class 在被加载的时候被放入永久区域。它和和存放实例的区域不同,GC 不会在主程序运行期对永久区域进行清理。所以这也导致了永久代的区域会随着加载的 Class 的增多而胀满,最终抛出 OOM 异常。

在 Java8 中,永久代已经被移除,被一个称为 “元数据区”(元空间)的区域所取代。

元空间的本质和永久代类似,都是对 JVM 规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。类的元数据放入 native memory, 字符串池和类的静态变量放入 java 堆中. 这样可以加载多少类的元数据就不再由 MaxPermSize 控制, 而由系统的实际可用空间来控。

问题四:堆是怎么构成的?

答:堆 = 新生代 + 老年代

其中,新生代 ( Young ) 被细分为 Eden 两个 Survivor 区域,这两个 Survivor 区域分别被命名为 From Survivor To Survivor ,以示区分。
默认的,Edem : from : to = 8 : 1 : 1 。可以通过参数 –XX:SurvivorRatio 来设定 ,即:
Survivor区和Eden区的比值

持续更新中....

参考博客:

Java内存垃圾回收(GC)原理_Zhang.Voi的博客-CSDN博客_java内存回收机制原理

https://www.jianshu.com/p/3d61a0e0e006

GC触发条件,堆的构成_水滴石穿007的博客-CSDN博客_gc触发条件

相关文章:

  • 第五届上海市青少年算法竞赛 T4 夹心饼干(思维、数学)
  • 刷好题,固基础-12
  • 点击广告就能日赚收益1000+?开发一款看广告赚收益的APP靠谱吗?
  • OpenHarmony实战开发-如何实现进入页面,点击动画卡片,动画播放并且文本发生变化。
  • c语言之结构体与函数传递
  • JWT技术选型以及相关功能的实现
  • xss.haozi.me靶场练习
  • C#中全局处理异常方式
  • 最新IE跳转Edge浏览器解决办法(2024.2.26)
  • Self-attention与Word2Vec
  • 基于华为atlas的分类模型实战
  • 消息中间件篇之Kafka-消息不丢失
  • 没有谷歌翻译,我该怎么办?
  • Java Web Spring核心之AOP的解析及实战(AOP的实现、切入点、Aspect Spring的持久化 Hibernate)
  • kali中实用的小工具
  • C++ 算法竞赛中的排序算法
  • 斯坦福大学吴恩达教授最新来信:AI, GPU和芯片的未来
  • 高薪程序员面试题精讲系列155之项目介绍,说说你最熟悉的项目,遇到了哪些困难?
  • “数据中台、读写分离、表分区”解决MySQL 单表数据量、并放量双高的效率瓶颈
  • 调用百度云语音转文本
  • SDWAN的功能和场景应用
  • JS 第三课(JS的变量类型和数据类型)
  • Matlab论文插图绘制模板第56期—曲面图(Surf)
  • 全志 Tina Linux 存储介质切换:eMMC,SPI NAND,SPI NOR,SD Card,SD NAND
  • FPGA—从加法运算理解流水线的作用
  • C++从入门到精通 C++98.11.14.17
  • 基于单片机的16×16点阵的滚动显示屏设计
  • LeetCode 940. 不同的子序列 II
  • 【VUE基础】webpack
  • 【漏洞复现-discuz-wooyun-命令执行】vulfocus/discuz-wooyun_2010_080723
  • SDWAN和MPLS谁才是最佳选择
  • 记一次失败的使用python selenium刷课学习通脚本(细节满满)+关于使用selenium的疑难杂症解决+json数据请求的疑难杂症+py冷门知识