0

0

了解 Java 中的垃圾收集:什么、为什么以及如何

碧海醫心

碧海醫心

发布时间:2024-11-27 20:59:06

|

789人浏览过

|

来源于dev.to

转载

了解 java 中的垃圾收集:什么、为什么以及如何

内存管理是编程的一个重要方面,java 为开发人员提供了自动垃圾收集机制来高效处理它。与 c 或 c 等语言开发人员必须手动分配和释放内存不同,java 的垃圾收集器 (gc) 负责回收未使用的内存,从而降低内存泄漏的风险。

在这篇博文中,我们将探讨垃圾回收是什么、为什么它很重要、它在 java 中如何工作以及使用它的一些最佳实践。

什么是垃圾收集?

java中的垃圾收集是自动识别和回收应用程序不再可达或不再需要的对象所占用的内存的过程。这些对象被标记为“垃圾”,并且它们的内存被回收以供重用。

主要特点:

  • 自动:java 虚拟机 (jvm) 自动管理内存。
  • 非确定性:无法预测垃圾回收发生的确切时间。
  • 标记和清除:大多数垃圾收集算法都涉及标记可达对象并清除不可达对象。

为什么垃圾收集很重要?

  1. 内存优化:释放未使用的内存,以确保应用程序有足够的空间继续运行。
  2. 简化开发:无需手动内存管理,减少开发人员的工作量和错误。
  3. 防止内存泄漏:识别并清理未使用的对象,确保不会不必要地消耗内存。

java 中的垃圾收集是如何工作的?

堆内存和对象生命周期

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 期间暂停。
  • 并行垃圾收集器(吞吐量收集器)

    阿里云AI平台
    阿里云AI平台

    阿里云AI平台

    下载
    • 最适合:需要高吞吐量的应用程序(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;
    }
}

说明:

  1. 当 person1 重新分配给 person2 时,对象“alice”变得不可访问。
  2. 垃圾收集器现在可以回收“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)。

要点

  1. 自动内存管理: 垃圾收集是 java 中的一种内置机制,可以简化内存管理。
  2. 世代模型: gc 通过不同方式处理短寿命和长寿命对象。
  3. 选择正确的 gc 算法: 将垃圾收集器与您的应用程序对吞吐量或低延迟的需求相匹配。
  4. 监控和优化: 定期分析堆使用情况和垃圾收集指标,以防止与内存相关的问题。

通过有效地理解和利用 java 的垃圾收集,您可以确保您的应用程序高效运行,并且不会出现内存泄漏和性能瓶颈。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

254

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1089

2024.03.01

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

761

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1568

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

651

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

1228

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

1204

2024.04.29

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号