了解 Java 中的垃圾收集:什么、为什么以及如何
来源:dev.to
时间:2024-12-13 22:52:01 392浏览 收藏
从现在开始,努力学习吧!本文《了解 Java 中的垃圾收集:什么、为什么以及如何》主要讲解了等等相关知识点,我会在golang学习网中持续更新相关的系列文章,欢迎大家关注并积极留言建议。下面就先一起来看一下本篇正文内容吧,希望能帮到你!
内存管理是编程的一个重要方面,java 为开发人员提供了自动垃圾收集机制来高效处理它。与 c 或 c 等语言开发人员必须手动分配和释放内存不同,java 的垃圾收集器 (gc) 负责回收未使用的内存,从而降低内存泄漏的风险。
在这篇博文中,我们将探讨垃圾回收是什么、为什么它很重要、它在 java 中如何工作以及使用它的一些最佳实践。
什么是垃圾收集?
java中的垃圾收集是自动识别和回收应用程序不再可达或不再需要的对象所占用的内存的过程。这些对象被标记为“垃圾”,并且它们的内存被回收以供重用。
主要特点:
- 自动:java 虚拟机 (jvm) 自动管理内存。
- 非确定性:无法预测垃圾回收发生的确切时间。
- 标记和清除:大多数垃圾收集算法都涉及标记可达对象并清除不可达对象。
为什么垃圾收集很重要?
- 内存优化:释放未使用的内存,以确保应用程序有足够的空间继续运行。
- 简化开发:无需手动内存管理,减少开发人员的工作量和错误。
- 防止内存泄漏:识别并清理未使用的对象,确保不会不必要地消耗内存。
java 中的垃圾收集是如何工作的?
堆内存和对象生命周期
java 的垃圾收集器在堆内存上运行,所有对象都存储在堆内存上。对象有不同的生命周期,垃圾收集器确保:
- 仍在使用的对象保留在内存中。
- 不再可达的对象(即没有引用)被标记为删除。
分代垃圾收集模型
java 使用分代模型来优化垃圾收集,基于以下假设:
- 大多数对象都是短暂的(例如,在方法中创建的临时对象)。
- 寿命长的对象不太可能成为垃圾。
堆分为以下区域:
-
年轻一代(或新一代):
- 用途:保存短期对象(例如临时变量、循环变量)。
- 部门:
- eden space:分配新对象的地方。
- 幸存者空间(s0 和 s1):在 eden 中的一次或多次垃圾回收中幸存下来后,对象将被移动到幸存者空间。
- 垃圾收集:
- minor gc 用于清理年轻代。
- 经常发生,因为这里的大多数物体的寿命都很短。
- 晋升:如果一个对象在一定数量的gc周期中幸存下来,它就会被晋升到老年代。
-
老一代(或终身一代):
- 用途:存储长期存在的对象,例如那些在整个应用程序生命周期中持续存在的对象。
- 垃圾收集:
- major gc(或 full gc)发生频率较低,但需要更长的时间,因为它涉及整个堆。
- 年轻代中的对象如果能存活足够的 gc 周期,就会在这里被提升。
- 大小:通常比年轻一代大。
-
永久代 (permgen) [java 8 之前]:
- 目的:
- 存储有关类、方法和其他 jvm 内部结构的元数据。
- 还存储静态字段和字符串文字。
- gc:
- 不像堆(年轻/老一代)那样动态管理,如果空间耗尽,可能会导致 outofmemoryerror: permgen space。
- 很少收集。
- 弃用:
- 在 java 8 中删除并替换为 metaspace。
- 元空间在本机内存中分配并动态增长,避免了许多与 permgen 相关的问题。
- 目的:
将内存分为几代可以让 gc 通过关注以下方面来优化其性能:
- 频繁、快速地清理短寿命对象(年轻一代)。
- 对长寿命对象(老一代)的清理频率较低,但更彻底。
后 java 8 变化(元空间):
- metaspace 取代了 permgen,并且位于本机内存而不是 jvm 堆中。
- 没有像permgen那样的固定大小;它可以根据需要增长,取决于可用的系统内存。
垃圾收集的阶段
- 标记:
- 通过遍历 gc 根的引用来识别所有可到达的对象(例如,局部变量、活动线程)。
- 扫地:
- 回收未引用对象占用的内存。
- 压缩(可选):
- 重新排列内存中的对象以消除碎片。
java 中的垃圾收集算法
jvm提供了多种垃圾回收算法,可以根据应用的需求进行选择。
-
串行垃圾收集器
- 最适合:单线程环境或小堆。
- 机制:使用单线程进行垃圾回收。
- 主要特征:更简单,但会导致应用程序在 gc 期间暂停。
-
并行垃圾收集器(吞吐量收集器)
- 最适合:需要高吞吐量的应用程序(java 8 中默认)。
- 机制:年轻代和老年代都使用多线程进行gc。
- 主要特征:减少暂停时间,但可能会影响 cpu 可用性。
-
g1 垃圾收集器(垃圾优先)
- 最适合:需要低延迟 gc 的应用程序(java 9 及更高版本中默认)。
- 机制:将堆划分为多个区域,并优先收集垃圾最多的区域。
- 主要特征:平衡暂停时间和吞吐量。
-
z 垃圾收集器 (zgc)
- 最适合:需要超低延迟 gc 的大型堆应用程序。
- 机制:同时执行大部分工作,并在毫秒范围内暂停。
- 主要特征:非常适合高达 tb 大小的堆。
-
shenandoah 垃圾收集器(shenandoah gc)
- 最适合:需要低延迟 gc 的中型到大型堆的应用程序。
- 机制:执行并发垃圾收集和压缩,通过与应用程序线程一起运行大多数操作来最大限度地减少暂停时间。
- 主要特征:通过在应用程序运行时压缩内存来专注于低暂停时间(通常为几毫秒)。
代码示例:对象如何变成垃圾
这是一个简单的示例,演示对象如何变得无法访问并有资格进行垃圾回收:
public class garbagecollectiondemo { public static void main(string[] args) { // object 1 is created person person1 = new person("alice"); // object 2 is created person person2 = new person("bob"); // reference of person1 is reassigned person1 = person2; // object "alice" is now unreachable // both person1 and person2 point to "bob" system.out.println(person1.name); // output: bob // at this point, "alice" object is eligible for garbage collection } } class person { string name; person(string name) { this.name = name; } }
说明:
- 当 person1 重新分配给 person2 时,对象“alice”变得不可访问。
- 垃圾收集器现在可以回收“alice”占用的内存。
如何触发垃圾收集
虽然您无法强制进行垃圾回收,但您可以使用以下方式向 jvm 建议:
system.gc();
为什么要避免显式调用?
- 垃圾收集是自动进行的,并由 jvm 进行优化。
- 调用 system.gc() 可能会破坏垃圾收集器的效率。
常见的垃圾收集问题
- 内存泄漏
当对象保持不必要的引用时发生,从而阻止垃圾收集。
示例:
import java.util.arraylist; import java.util.list; public class memoryleakexample { static list<object> list = new arraylist<>(); public static void main(string[] args) { for (int i = 0; i < 10000; i++) { list.add(new object()); // keeps adding objects to the static list } } }
这里,列表保留了对所有对象的引用,使它们不符合gc。
- 内存不足错误
堆已满且无法回收内存时发生。
解决方案:
使用 jvm 选项增加堆大小:
java -xmx1024m myapp
垃圾收集的最佳实践
- 避免不必要的对象创建:
- 尽可能重用对象。
- 使用轻量级对象来存储短期数据。
- 取消未使用的引用:
- 当不再需要引用时将其设置为 null。
myObject = null;
- 明智地使用集合:
- 从列表或地图等集合中删除未使用的元素。
- 监控垃圾收集:
- 使用 jconsole 或 visualvm 等工具来监控 gc 活动。
- 选择合适的垃圾收集器:
- 使用 jvm 选项根据应用程序需求定制 gc(例如,对于 g1 收集器,-xx: useg1gc)。
要点
- 自动内存管理: 垃圾收集是 java 中的一种内置机制,可以简化内存管理。
- 世代模型: gc 通过不同方式处理短寿命和长寿命对象。
- 选择正确的 gc 算法: 将垃圾收集器与您的应用程序对吞吐量或低延迟的需求相匹配。
- 监控和优化: 定期分析堆使用情况和垃圾收集指标,以防止与内存相关的问题。
通过有效地理解和利用 java 的垃圾收集,您可以确保您的应用程序高效运行,并且不会出现内存泄漏和性能瓶颈。
今天关于《了解 Java 中的垃圾收集:什么、为什么以及如何》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
450 收藏
-
332 收藏
-
332 收藏
-
311 收藏
-
346 收藏
-
377 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习