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

四、JVM原理-4.2、内存管理

4.2、内存管理

4.2.1、JVM是如何判断一个对象是否可以被回收的

答:
在Java中,JVM使用垃圾回收算法来判断一个对象是否可以被回收。JVM使用的垃圾回收算法主要有两种:引用计数法和可达性分析法。

  1. 引用计数法:每个对象都有一个计数器,当有一个引用指向该对象时,计数器加1,当引用失效时,计数器减1。当计数器的值为0时,表示该对象不再被引用,可以被回收。

  2. 可达性分析法:JVM从一组根对象(如线程栈中的本地变量和静态变量)开始,通过遍历对象的引用链来确定一个对象是否可达。如果一个对象无法通过任何引用链与根对象连接在一起,那么该对象就被判定为不可达,可以被回收。

扩展:
实际上,Java中并没有采用引用计数算法来判断对象是否可以被回收。引用计数法的确存在一些缺点,例如无法解决循环引用的问题,即使两个对象互相引用,但其它部分代码已经不再引用它们,它们仍然无法被回收。
JVM通过使用可达性分析法来确定哪些对象是可达的,并将未被引用的对象标记为垃圾,然后进行回收。

4.2.2、谈谈你对JVM中主要GC算法的理解

答:
JVM中的主要GC算法是标记-清除算法、复制算法、标记-整理算法和分代收集算法。

  1. 标记-清除算法(Mark and Sweep):这是最基本的GC算法之一。算法分为两个阶段,首先标记所有活跃对象,然后清理(回收)那些未被标记的对象。该算法的缺点是会产生大量的内存碎片。

  2. 标记-复制算法(Copying):这个算法将内存空间分为两个区域,一半是用于存放活跃对象的From区域,另一半则为空闲的To区域。当From区域的空间被占满时,将活跃对象复制到To区域,并且清理From区域中的所有对象。该算法的优点是避免了内存碎片问题,但是也需要额外的一半内存空间来进行复制。

  3. 标记-整理算法(Mark and Compact):这个算法结合了标记-清除算法和复制算法的优点。首先标记所有活跃对象,然后将它们压缩到内存的一端,然后清理掉整个内存空间的剩余部分。这样可以保持内存的连续性,但是会产生一定的内存移动开销。

  4. 分代回收算法(Generational):这是一种基于对象存活时间的GC算法。根据对象的存活时间将内存分为新生代和老年代。新生代中的对象通常会被频繁回收,所以可以使用复制算法来进行GC;而老年代中的对象存活时间较长,所以可以使用标记-清除或标记-整理算法进行GC。这种算法可以根据不同代的对象特点进行相应的优化,提高GC效率。

扩展:
分代回收算法是一种常用的垃圾回收算法,它根据对象的存活时间将内存分为不同的代,通常分为新生代和老年代,新生代包括Eden区和幸存区(包括From区和To区)。下面是分代回收算法的详细过程:

  1. 对象分配:当Java程序需要创建对象时,对象首先被分配到Eden区域。
  2. Minor GC(新生代回收):当Eden区域满了时,触发Minor GC。Minor GC使用的是标记复制算法,主要包括以下步骤:
    • 标记:从根对象开始,对新生代的对象进行可达性分析,标记所有活跃对象。
    • 复制:将所有活跃对象从Eden区域和From区域复制到To区域,并清理掉Eden区域和From区域中的无效对象。每经历一次minor GC,没被回收的对象就会在From区和To区移动一次,每移动一次,年龄加一。
    • 年龄提升:将To区域中的对象的年龄加1,若年龄达到阈值(通常为15),则被晋升到老年代。一个对象的GC年龄是存储在对象头中的,对象头中有4位是用于存储GC年龄的,4位能够存储的最大数值为15,所以JVM分代年龄值设置成了15
    • 清理:清理幸存区的无效对象。
  3. 对象晋升:在经过多次Minor GC后,如果对象在To区域经历了多次复制并仍然存活,GC年龄达到15岁时,那么它将会被晋升到老年代。
  4. Full GC(老年代回收):当老年代空间不足或者对象进入老年代失败时,触发Full GC。Full GC会对整个堆内存进行回收,包括新生代和老年代。Full GC的过程较为复杂,主要包括标记和整理阶段,Full GC使用标记整理算法进行回收

4.2.3、JVM分代年龄为什么是15次?

答:
一个对象的GC年龄是存储在对象头中的,对象头中有4位存储空间是用于存储GC年龄的,4位能够存储的最大数值为15,所以JVM分代年龄值设置成了15。

4.2.4、JVM为什么使用元空间替换永久代?

答:
元空间和永久代都是运行时数据区中不同结构的方法区。永久代是JDK1.8以前的方法区,元空间是JDK1.8及其之后的方法区。

  1. 内存管理:永久代在Java 8之前是使用JVM堆内存的一部分,并且有一个固定的大小。由于永久代是使用堆内存的一部分,因此永久代的大小对整个Java应用程序的内存管理具有很大的限制。而元空间是使用本地内存,它不再受到堆内存的限制,可以根据需要动态地分配和释放内存,从而提供更好的内存管理。

  2. 类的元数据存储:永久代主要用于存储类的元数据信息,如类的结构、方法、字段等。而在一些复杂的应用程序中,类的元数据信息可能非常庞大,使得永久代的大小很容易被耗尽。通过使用元空间,可以将类的元数据信息存储在本地内存中,从而有效地解决了永久代大小的限制问题。

  3. 垃圾回收:在永久代中,垃圾回收主要是通过调用Full GC来进行的,这会导致应用程序的停顿时间增加。而在元空间中,使用的是JVM的垃圾回收器,可以根据需要动态地进行部分或增量垃圾回收,从而减少应用程序的停顿时间。

扩展:
总结:使用元空间替代永久代主要是为了提供更好的内存管理、解决永久代大小限制问题以及降低垃圾回收带来的停顿时间。

4.2.5、JDK1.8与JDK1.7中的Java内存区域有什么区别?

对Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每个对象的new操作去写配对的delete/free 代码,不容易出现内存泄露和内存溢出的问题。不过,仍然需要Java虚拟机是如何使用内存的,方便我们定位内存泄露和内存溢出的问题:

Java虚拟机在执行Java程序时会把它所管理的内存划分为若干个部分,这些区域有各自的用途、创建和销毁时间,有的区域随着虚拟机进程的启动而一直存在,有的则依赖用户线程的启动和结束而建立和销毁。
JVM结构
JDK 1.8 之前的内存分布:
JDK1.7及以前的运行时数据区结构
JDK 1.8 之后的内存分布:
JDK1.8及其以后的运行时数据区结构
本机直接内存的分配不会受到 Java 堆的限制,但是,既然是内存就会受到本机总内存大小以及处理器寻址空间的限制。参考原文链接https://www.cnblogs.com/jjfan0327/p/12778954.html


http://www.kler.cn/a/310851.html

相关文章:

  • 新版 idea 编写 idea 插件时,启动出现 ClassNotFound
  • 【MySQL】约束
  • JSON-RPC-CXX深度解析:C++中的远程调用利器
  • 类别变量分析——卡方独立性检验卡方拟合优度检验
  • 嵌入式硬件杂谈(一)-推挽 开漏 高阻态 上拉电阻
  • 在 Ubuntu 上安装 `.deb` 软件包有几种方法
  • 计算机视觉(CV)技术是指计算机系统通过模拟人类视觉系统来识别、理解和解释图像和视频的能力。它可以在各种领域中发挥巨大作用,但也面临一些挑战。
  • tasklist命令的应用实例
  • 力扣150题——位运算
  • 小程序开发设计-第一个小程序:创建小程序项目④
  • Java学习路线指南
  • PowerShell install 一键部署Oracle23ai
  • 基于安卓的音乐app设计与实现(全套)
  • Android 开发高频面试题之——Flutter
  • 【JVM】类加载过程|双亲委派模型
  • RTX 4090 系列即将停产,RTX 5090 系列蓄势待发
  • 【系统架构设计】系统的可靠性分析与设计
  • 接口自动化框架入门(requests+pytest)
  • 最好用的翻译器:什么是DeepL?如何订阅支付DeepL,订阅DeepL Pro以及申请DeepL API?
  • 蓝桥杯—STM32G431RBT6按键的多方式使用(包含软件消抖方法精讲)从原理层面到实际应用(一)
  • TS - tsconfig.json 和 tsconfig.node.json 的关系,如何在TS 中使用 JS 不报错
  • 产品经理注意!11月NPDP考试预报名已开启
  • Oracle 11gR2打PSU补丁详细教程
  • 监控系列之-Grafana面板展示及制作
  • Flutter 优化技巧分享
  • Linux 内存分析工具 —— heaptrack