Java 高级篇:JVM 垃圾回收机制

2023-11-05

Java 语言的一大优势在于其具有自动垃圾回收(Garbage Collection,GC)机制,让开发者无需关心内存的分配与释放。

本文将详细解析 JVM(Java Virtual Machine)中的垃圾回收机制,带你深入了解 GC 如何运作,以及如何优化垃圾回收性能。

一、垃圾回收基本原理

在 Java 语言中,对象的内存空间由 JVM 自动管理。当 JVM 确定某个对象不再被使用时,它将自动回收这个对象所占用的内存。这种自动回收内存的机制称为垃圾回收。

垃圾回收的主要任务包括两个方面:

  1. 发现无用对象:JVM 通过对象的可达性分析来判断对象是否仍在使用。如果一个对象不再被其他对象引用,那么它就被认为是无用的,可以被回收。

  1. 回收无用对象所占用的内存:JVM 释放无用对象所占用的内存,以便其他对象使用。

二、JVM 内存结构

要了解垃圾回收机制,首先要了解 JVM 的内存结构。JVM 将内存划分为以下几个区域:

  1. 堆(Heap):存储对象实例,是垃圾回收的主要区域。

  1. 方法区(Method Area):存储已被加载的类信息、常量、静态变量等数据。

  1. 栈(Stack):存储局部变量表、操作数栈、动态链接、方法出口等信息。

  1. 程序计数器(PC Register):存储当前线程执行的字节码行号。

垃圾回收主要针对堆和方法区进行。

三、垃圾收集器(Garbage Collector)

JVM 提供了多种垃圾收集器,它们各自采用不同的算法,以满足不同场景的需求。常见的垃圾收集器有:

  1. Serial Collector:单线程收集器,适用于客户端应用。

  1. Parallel Collector:多线程收集器,适用于多核服务器端应用。

  1. CMS(Concurrent Mark Sweep)收集器:并发收集器,适用于对响应时间有较高要求的应用。

  1. G1(Garbage-First)收集器:基于区域划分的收集器,适用于大内存应用。

四、垃圾回收算法

  1. 标记-清除(Mark-Sweep)算法:

标记-清除算法分为两个阶段:标记阶段和清除阶段。在标记阶段,垃圾收集器遍历堆中的对象,将不再使用的对象进行标记。在清除阶段,垃圾收集器将标记的对象从内存中移除。标记-清除算法的主要缺点是内存碎片化,可能导致后续对象分配时找不到足够的连续内存。

  1. 标记-整理(Mark-Compact)算法:

为解决标记-清除算法的内存碎片化问题,标记-整理算法在清除阶段进行了优化。在标记阶段与标记-清除算法相同,都是对不再使用的对象进行标记。然而,在清除阶段,标记-整理算法会将存活的对象压缩到内存的一端,从而避免内存碎片化。这种算法的缺点是移动对象的开销较大。

  1. 复制(Copying)算法:

  • 复制算法将堆内存分为两个相等的区域,每次只使用其中一个区域。

  • 当这个区域的内存用完时,垃圾收集器会将存活的对象复制到另一个区域,并将已使用区域清空。这种算法避免了内存碎片化和对象移动的问题,但代价是可用内存空间减半。

  1. 分代收集(Generational Collection)算法:

  • 大部分对象的生命周期都很短暂,因此分代收集算法将堆内存划分为新生代和老年代。新生代使用复制算法,老年代使用标记-整理算法。

  • 当对象在新生代中经历了一定次数的垃圾回收后,它将被晋升到老年代。分代收集算法充分利用了对象生命周期的特点,提高了垃圾回收的效率。

五、垃圾回收实战与优化:

为了更好地理解垃圾回收机制及优化方法,我们使用一个简单的 Java 程序来模拟内存泄漏。

import java.util.ArrayList;
import java.util.List;
public class GCDemo {
   public static void main(String[] args) {
       List<Object> objects = new ArrayList<>();
       while (true) {
           objects.add(new byte[1024 * 1024]);
      }
  }
}

该程序会不断地分配内存,从而触发垃圾回收。我们可以使用 Java VisualVM 工具观察程序运行时的内存使用情况和垃圾回收次数。

为了优化垃圾回收,可以尝试以下方法:

  1. 调整堆内存大小:可以通过设置 JVM 参数 -Xms-Xmx 来调整堆内存的初始大小和最大大小。适当增加堆内存大小可以减少垃圾回收次数,提高程序运行效率。

java -Xms512m -Xmx1024m GCDemo
  1. 选择合适的垃圾收集器:根据应用场景选择合适的垃圾收集器,以达到最佳的垃圾回收性能。可以使用 -XX:+UseSerialGC-XX:+UseParallelGC-XX:+UseConcMarkSweepGC-XX:+UseG1GC 参数选择不同的垃圾收集器。

java -Xms512m -Xmx1024m -XX:+UseParallelGC GCDemo
  1. 调整新生代与老年代比例:使用 -XX:NewRatio 参数可以调整新生代与老年代的比例。适当调整新生代与老年代比例可以减少对象晋升到老年代的次数,降低老年代垃圾回收的频率。

java -Xms512m -Xmx1024m -XX:+UseParallelGC -XX:NewRatio=2 GCDemo
  1. 监控并分析垃圾回收日志:可以使用 -Xloggc 参数将垃圾回收日志输出到文件,利用 GC 日志分析工具(如 GCViewer)分析垃圾回收的情况,从而找到合适的优化方法。

java -Xms512m -Xmx1024m -XX:+UseParallelGC -XX:NewRatio=2 -Xloggc:gc.log GCDemo

六、总结

本文详细介绍了 JVM 垃圾回收机制的原理、内存结构、垃圾收集器、垃圾回收算法,以及实战与优化方法。通过深入了解 JVM 的垃圾回收机制,我们可以更好地优化 Java 程序的性能,降低内存占用,提高系统稳定性。

垃圾回收机制是 Java 语言的核心优势之一,但也并非完美无缺。作为开发者,我们应该充分了解垃圾回收的原理和限制,避免产生内存泄漏等问题,并在需要时进行适当的优化。同时,不断学习和实践,掌握更多的 Java 高级技能,以提升我们的开发能力和水平。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 高级篇:JVM 垃圾回收机制 的相关文章

  • 控制Android的前置LED灯

    我试图在用户按下某个按钮时在前面的 LED 上实现 1 秒红色闪烁 但我很难找到有关如何访问和使用前置 LED 的文档 教程甚至代码示例 我的意思是位于 自拍 相机和触摸屏附近的 LED 我已经看到了使用手电筒和相机类 已弃用 的示例 但我
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • 磁模拟

    假设我在 n m 像素的 2D 表面上有 p 个节点 我希望这些节点相互吸引 使得它们相距越远吸引力就越强 但是 如果两个节点之间的距离 比如 d A B 小于某个阈值 比如 k 那么它们就会开始排斥 谁能让我开始编写一些关于如何随时间更新
  • 路径中 File.separator 和斜杠之间的区别

    使用有什么区别File separator和一个正常的 在 Java 路径字符串中 与双反斜杠相反 平台独立性似乎不是原因 因为两个版本都可以在 Windows 和 Unix 下运行 public class SlashTest Test
  • Mockito when().thenReturn 不必要地调用该方法

    我正在研究继承的代码 我编写了一个应该捕获 NullPointerException 的测试 因为它试图从 null 对象调用方法 Test expected NullPointerException class public void c
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • 十进制到八进制的转换[重复]

    这个问题在这里已经有答案了 可能的重复 十进制转换错误 https stackoverflow com questions 13142977 decimal conversion error 我正在为一个类编写一个程序 并且在计算如何将八进
  • Java TestNG 与跨多个测试的数据驱动测试

    我正在电子商务平台中测试一系列商店 每个商店都有一系列属性 我正在考虑对其进行自动化测试 是否有可能有一个数据提供者在整个测试套件中提供数据 而不仅仅是 TestNG 中的测试 我尝试不使用 testNG xml 文件作为机制 因为这些属性
  • 为什么HashMap不能保证map的顺序随着时间的推移保持不变

    我在这里阅读有关 Hashmap 和 Hashtable 之间的区别 http javarevisited blogspot sg 2010 10 difference Between hashmap and html http javar
  • 使用Caliper时如何指定命令行?

    我发现 Google 的微型基准测试项目 Caliper 非常有趣 但文档仍然 除了一些示例 完全不存在 我有两种不同的情况 需要影响 JVM Caliper 启动的命令行 我需要设置一些固定 最好在几个固定值之间交替 D 参数 我需要指定
  • getResourceAsStream() 可以找到 jar 文件之外的文件吗?

    我正在开发一个应用程序 该应用程序使用一个加载配置文件的库 InputStream in getClass getResourceAsStream resource 然后我的应用程序打包在一个 jar文件 如果resource是在里面 ja
  • 总是使用 Final?

    我读过 将某些东西做成最终的 然后在循环中使用它会带来更好的性能 但这对一切都有好处吗 我有很多地方没有循环 但我将 Final 添加到局部变量中 它会使速度变慢还是仍然很好 还有一些地方我有一个全局变量final 例如android Pa
  • Java Integer CompareTo() - 为什么使用比较与减法?

    我发现java lang Integer实施compareTo方法如下 public int compareTo Integer anotherInteger int thisVal this value int anotherVal an
  • Java执行器服务线程池[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 如果我使用 Executor 框架在
  • 无法捆绑适用于 Mac 的 Java 应用程序 1.8

    我正在尝试将我的 Java 应用程序导出到 Mac 该应用程序基于编译器合规级别 1 7 我尝试了不同的方法来捆绑应用程序 1 日食 我可以用来在 Eclipse 上导出的最新 JVM 版本是 1 6 2 马文 看来Maven上也存在同样的
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • 在 Maven 依赖项中指定 jar 和 test-jar 类型

    我有一个名为 commons 的项目 其中包含运行时和测试的常见内容 在主项目中 我添加了公共资源的依赖项
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 如何修复 JNLP 应用程序中的“缺少代码库、权限和应用程序名称清单属性”?

    随着最近的 Java 更新 许多人都遇到了缺少 Java Web Start 应用程序的问题Codebase Permissions and Application name体现属性 尽管有资源可以帮助您完成此任务 但我找不到任何资源综合的
  • 将 List 转换为 JSON

    Hi guys 有人可以帮助我 如何将我的 HQL 查询结果转换为带有对象列表的 JSON 并通过休息服务获取它 这是我的服务方法 它返回查询结果列表 Override public List

随机推荐

  • 想做硬件开发的人员必看

    转眼间 已经毕业一年了 在这一年中经历了很多 工作已经换了两个了 住的地方好像已经换了两三个了 这中间不包括跨地区生活 我刚大四的时候 应聘一家网络公司做硬件开发 03年的时刚过完年 我就千里迢迢的来到了一个陌生的地方 在这以前 我从来没有
  • java 密码扩展无限制权限策略文件

    开发十年 就只剩下这套Java开发体系了 gt gt gt 因为某些国家的进口管制限制 Java发布的运行环境包中的加解密有一定的限制 比如默认不允许256位密钥的AES加解密 解决方法就是修改策略文件 官方网站提供了JCE无限制权限策略文
  • 灯泡开关

    初始时有 n 个灯泡处于关闭状态 第一轮 你将会打开所有灯泡 接下来的第二轮 你将会每两个灯泡关闭第二个 第三轮 你每三个灯泡就切换第三个灯泡的开关 即 打开变关闭 关闭变打开 第 i 轮 你每 i 个灯泡就切换第 i 个灯泡的开关 直到第
  • 强的离谱,如何用Python兼职接单?攻略来袭!大数据推送给即将暴富得人!

    一 python爬虫是可以做副业的 主要是爬取网站 小程序或者APP的数据 对数据进行分析与处理 或者直接向客户提供爬虫程序与技术支持 当初学会Python那会儿 有朋友来介绍我去接私活 是为一家公司做网站 那一单我赚了3 5K 从那之后逐
  • Java多线程抢票代码

    public class Main public static class Ticket implements Runnable 票 private int tic 100 Override public void run while tr
  • Java类排序

    今天上课 老师讲到Arrays sor 的时候说 这个可以对数组进行排序 于是当时脑海中立刻浮现出两个问题 一 如果对类排序 一定要把实现什么接口 二 实现了这个接口 Java怎么知道一个类是否实现了某个接口 于是带着这个问题做了一翻查找
  • 【Maya基础脚本开发】让已经冻结变换的对象移动到世界原点,并重新冻结

    让已经冻结变换的对象移动到世界原点 并重新冻结 import maya cmds as cmds def reset to origin node node pos False if not node pos node pos cmds x
  • opencv3.4.2 cv2.dnn.blobFromImage

    opencv3 4 2 cv2 dnn blobFromImage 在做object detction的项目的时候 遇到一个问题 就是将tensorflow训练好的模型 来进行物体检测和将tensorflow训练好的模型导出成pb和pbtx
  • Solidworks标注螺纹孔的时候如何显示螺纹线

    Solidworks标注螺纹孔的时候如何显示螺纹线 https jingyan baidu com article 22fe7cedfd81ca3003617f5c html
  • win 7旗舰版开机提示 :explorer.exe-无法找到入口

    Win7 SP1 64位开机报错 explorer exe 无法找到入口 explorer exe 无法找到入口 解决办法 方法1 1 病毒原因导致的 建议将杀毒软件升级到最新版本 然后再安全模式下全盘扫描病毒 2 软件修复 可以通过金山卫
  • 两台服务器间进行文件传输

    目录 方法1 使用SCP 方法2 使用rsync 使用SSH密钥 两台服务器之间进行文件传输通常可以使用SCP Secure Copy Protocol 或rsync命令 这两种方法都是在UNIX和Linux系统上常用的工具 用于安全地复制
  • Error: 'C:\Keil\C51\BIN\SiC8051F.dll' not found 解决办法

    Error C Keil C51 BIN SiC8051F dll not found 解决办法 将C Keil UV3文件加下的两个文件USBHID dll uv3 cdb拷贝到C Keil UV4下
  • kali2021.2 安装及parallels tools

    看到网上十分零碎的安装方法 这里汇总了一下 经测试已成功 https www wolai com ckwalter s1Y51qyJDu7T4jv5hgdzB8 theme dark
  • 将代码复制到word里保留格式_如何让word中代码更美观

    转载 知乎 大块小屋 原文链接 https zhuanlan zhihu com p 108483150 写论文遇到最头大的事情 就是在word中插入代码时 格式全乱了 非常不美观 怎么又快又美的在word中插入代码 怎么让word中的代码
  • Linux下的多进程编程初步(转载)

    最近在学习linux环境高级编程 多进程编程算是编程中的最重要的一个部分了 本文让我学习和明白了很多 所以转载过来 让更多想多线程编程的人学习 只有顶到首页才能让更多的人学习 文章摘要 多线程程序设计的概念早在六十年代就被提出 但直到八十年
  • Tomcat启动乱码问题解决

    Tomcat 控制台UTF 8乱码问题 1 修改cmd的编码格式 快捷键win R打开运行程序 输入regedit打开注册表 找到以下路劲并且修改 HKEY LOCAL MACHINE SOFTWARE Microsoft Command
  • list怎么删除元素和ConcurrentModificationException

    当面试官 怎么删除list里面的元素 我 用for循环 活着迭代器 举例 循环 迭代器 看出什么问题了吗 对同一个集合遍历的不能删除 怎么解决 1 拷贝一份 一个用来遍历 一个用来删除 2 不用list的remove方法 用迭代器的remo
  • 【马士兵】Python基础--12

    Python基础 12 文章目录 Python基础 12 字符串比较 字符串切片 格式化字符串 字符串的编码与解码 知识点总结 字符串比较 print apple gt app print aanan gt banan print ord
  • RabbitMQ消息队列的总结

    什么是消息队列 MQ全称为MessageQueue 消息队列 MQ 是一种应用程序对应用程序的通信方法 应用程序通过写和检索出入列队的针对应用程序的数据 消息 来通信 而无需专用连接来链接它们 消息传递指的是程序之间通过在消息中发送数据进行
  • Java 高级篇:JVM 垃圾回收机制

    Java 语言的一大优势在于其具有自动垃圾回收 Garbage Collection GC 机制 让开发者无需关心内存的分配与释放 本文将详细解析 JVM Java Virtual Machine 中的垃圾回收机制 带你深入了解 GC 如何