首页 > 系统相关 >深入理解JVM垃圾收集器与内存分配策略

深入理解JVM垃圾收集器与内存分配策略

时间:2024-12-07 09:02:06浏览次数:8  
标签:收集器 对象 回收 GC 垃圾 JVM 内存

1. 什么是垃圾?

在Java虚拟机中,“垃圾”指的是内存中不再使用或不可达的对象。垃圾收集器(GC)的主要任务就是识别并回收这些垃圾对象,释放内存资源。在JVM中,垃圾收集器管理的是堆(Heap)和方法区(Method Area)中的对象,它们的生命周期是动态的,需要在运行时进行分配和回收。

2. 对象是否已经死了?

JVM使用可达性分析算法来判断对象是否是垃圾。通过GC Roots(GC根节点)开始,沿着引用链向下搜索,若某个对象无法通过GC Roots访问,则认为它是垃圾,能够被回收。常见的GC Roots包括:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象,比如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等
  • 方法区中类静态属性引用的对象,比如Java类的引用类型静态变量
  • 方法区中常量引用的对象,比如字符串常量池(String Table)里的引用
  • 本地方法栈JNI(Native方法)引用的对象
  • Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NPE,OOM)等,还有系统类加载器
  • 所有被同步锁(synchronized关键字)持有的对象
  • 反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等

3. 什么时候回收垃圾?

垃圾回收通常在以下两种情况下触发:

  • 内存分配失败:当堆内存不足以分配新对象时,GC会被触发。
  • System.gc():开发者可以通过显式调用System.gc()来请求垃圾回收。

4. 引用

JVM提供了不同的引用类型来管理对象的生命周期,帮助开发者控制对象的回收时机。

4.1 强引用

普通的引用(如Object obj = new Object();)属于强引用。当一个对象具有强引用时,GC不会回收该对象。

4.2 软引用

软引用用于内存不足时进行回收,JVM会尽量保留软引用对象,只有在内存紧张时才会回收。

4.3 弱引用

弱引用的对象只能存活到下一个GC发生时,垃圾回收器无论如何都会回收弱引用的对象。

4.4 虚引用

虚引用不会影响对象的生命周期,主要用于在对象被GC回收时做一些清理工作。

5. 垃圾收集算法

垃圾收集的核心是如何有效管理堆内存中的对象,JVM使用不同的垃圾收集算法来进行优化。

5.1 标记-清除算法

标记-清除算法分为两步:标记所有需要回收的对象,随后清除这些对象。缺点是效率较低,并且会造成内存碎片。

5.2 标记-复制算法

标记-复制算法将堆内存分为两块,每次只使用一块,当这块内存填满时,将存活对象复制到另一块并清理已使用的内存。此算法效率较高,但需要额外的内存空间。

5.3 标记-整理算法

与标记-清除算法类似,但是整理算法将所有存活对象移动到内存的一端,然后清理掉边界以外的内存,避免了内存碎片的问题。

6. HotSpot的算法实现细节

6.1 枚举根节点

GC的第一步是找到所有的根节点,这些根节点是GC Roots,通过它们可以遍历到所有可达的对象。在HotSpot中,使用OopMap来标记对象引用位置,帮助GC高效地找到根节点。

6.2 安全点(Safepoint)

安全点是JVM执行时程序中可暂停的点,GC只能在这些点暂停线程并进行垃圾回收。通过安全点,JVM能在不干扰程序执行的情况下进行GC。

6.3 安全区 (Safe Region)

安全区是指一段不会改变引用关系的代码区域,在这段代码执行时,GC可以安全进行。

6.4 记忆集与卡表

为了优化跨代引用带来的性能问题,HotSpot使用记忆集和卡表记录哪些对象之间存在引用关系,以减少每次GC时的检查范围,提高效率。

7. 垃圾收集器

JVM提供了多种垃圾收集器,每种垃圾收集器适用于不同的应用场景。

7.1 Serial收集器

Serial收集器是单线程的,适用于客户端模式,内存受限的环境。它的优点是内存消耗最小。

7.2 ParNew收集器

ParNew是Serial收集器的多线程版本,适用于服务端模式,能够提高垃圾回收的吞吐量。

7.3 Parallel Scavenge收集器

Parallel Scavenge收集器以吞吐量为目标,通过并行回收提高性能,适用于对吞吐量要求较高的应用。

7.4 Serial Old收集器

Serial Old收集器是Serial收集器的老年代版本,适用于客户端模式。

7.5 Parallel Old收集器

Parallel Old收集器是Parallel Scavenge收集器的老年代版本,支持多线程并发回收。

7.6 CMS收集器

CMS收集器旨在减少GC停顿时间,适用于对响应时间要求高的应用。

7.7 Garbage First收集器

G1收集器采用Region堆内存布局,目标是低延迟和高吞吐量,适用于大内存和大并发的应用。它是JVM 9及以后的默认收集器。

8. 内存分配与回收策略

8.1 年轻代(Young Generation)

年轻代用于存放新创建的对象,新生代对象存活率较低,回收效率高。新生代使用复制算法进行回收,分为Eden区和两个Survivor区。

8.2 老年代(Old Generation)

老年代存放存活较长时间的对象,采用标记-整理算法回收。长期存活的对象会晋升到老年代。

总结

JVM的垃圾收集机制通过多种垃圾收集算法和策略来优化内存回收,提升程序性能。理解不同垃圾收集器的特点及内存分配策略,能够帮助开发者更好地管理Java应用的内存,减少垃圾回收带来的性能损耗。同时,选择合适的垃圾收集器和内存策略,可以在不同场景下提升应用的响应速度和吞吐量。

标签:收集器,对象,回收,GC,垃圾,JVM,内存
From: https://blog.csdn.net/fulai00/article/details/143906164

相关文章

  • JVM, JRE 和 JDK
    JRE:JavaRuntimeEnvironment,Java运行环境.JDK:JavaDevelopmentKit,Java开发工具包.JRE=JVM+核心类库+运行工具JDK=JVM+核心类库+开发工具JVM:JavaVirtualMachine,Java虚拟机.核心类库:Java已经写好的东西,直接拿来用即可.开发工具:包括jav......
  • 数据在内存中的存储
    数据类型的介绍char    //字符数据类型short   //短整型int    //整形long    //长整型longlong //更长的整形float   //单精度浮点数double   //双精度浮点数这些都是我们常见的基本的内置类型以及了解它们所占存......
  • 常规加载器技术(Conventional Loader Techniques)主要用于操作系统中,负责将程序加载到内
    在Web开发中,常规加载器和高阶技巧加载器(或优化器)是实现更高效资源加载和提升性能的关键技术。常规加载器通常是一些基础的加载机制,而高阶技巧加载器则是更高级的优化方法,能够精细化地控制资源的加载时机和顺序,提升页面的加载性能和用户体验。常规加载器(基础加载器)懒加载(Lazy......
  • C/C++当中的内存对齐
    一:为什么要存在内存对齐  对与计算机而言,一次性可以取出处理的单元大小为字,在32位系统下,一次性可以取出4个字节,而在64位系统下,一次性可以取出8个字节,而一个地址对应一个内存单元,如果计算机按照挨着一个字节一个字节的来存储数据,那么计算机的内存一定是最节省的状态,但是很......
  • 一次彻底掌握数据中心级的JVM调优实战经验
    出现内存溢出的场景通常发生在应用程序中存在内存泄漏、对象生命周期过长、对象频繁创建但未能及时回收等问题。以下是几个真实的业务场景,结合内存溢出问题,并从多个角度提出优化方法,来提高内存使用效率。场景1:大量业务数据缓存导致堆内存溢出场景描述:一个企业级Web应......
  • 1 初识JVM
    想要对java虚拟机更深入的了解,可以查看《HotSpot实战》。需要电子版的请扫我头像关注我的个人号,发送000006领取电子书我们知道java程序是把java源文件编译成字节码.class文件,然后交给JVM执行。那么java到底是解释执行还是编译执行的语言呢?这个没有固定的答案,具体要要看用......
  • MySQL数据库写入异常,主库内存溢出,扩容+清理buff/cach!很开门
    MySQL数据库写入异常,主库内存溢出,扩容+清理buff/cach!很开门最近数据出现了两次写入异常报错如下:org.springframework,jdbc.UncategorizedsQlException:PreparedstatementCallback;uncategzed50LExcention[sql语句]TheMysOlserverisrunningwiththe--read-onlyoption......
  • nginx中添加lua模块,结合exporter计算内存使用率动态负载均衡调度
    一、nginx中添加lua模块1、安装依赖yuminstallgccgcc++readline-develwgetvimbash-completionpcrepcre-develzlibzlib-developensslopenssl-develunziplualua-devel-y2、编译安装luajit2wgethttps://github.com/openresty/luajit2/archive/refs/tags/v2......
  • C:内存管理
    内存管理动态内存分配可以在程序运行的时候临时决定需要分配的存储区个数,这种分配方式叫动态内存分配为了管理动态分配内存需要使用一组标准函数,这些标准函数需要包含stdlib.h头文件malloc函数可以动态分配一组连续的存储区这个函数需要一个整数类型的参数表示希望分配到字......
  • jvm内存结构详解
    JVM内存结构是Java程序运行的核心,它管理着程序运行时所需的内存空间,确保内存分配、回收以及线程之间的安全和高效通信。以下是JVM内存结构的详细解析:1. 程序计数器(ProgramCounterRegister):• 每个线程都有自己的程序计数器,用于记录当前线程正在执行的字节码指令的地址。......