GC机制和算法

本文深入解析Java垃圾回收机制,涵盖JVM内存管理、不同代的处理方式、引用类型及GC算法,详细介绍串行、并行、CMS和G1等垃圾收集器的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 概述

Java GC 垃圾回收机制,Java 和 C++的主要区别之一

出现问题: 内存泄漏,内存溢出(OutofMemory)

为何要使用: 为了写出高性能的应用程序

 

2. jvm内存管理

基本知识详见

2.1 方法区

存放类信息(类名,修饰符),类中静态变量,final常量,类属性和方法

方法区是全局共享的,在一定条件下它也会被GC。当方法区使用的内存超过它允许的大小时,就会抛出OutOfMemory:PermGen Space异常。

GC条件苛刻,这块区域被称为持久代,主要针对常量池和已加载的类的卸载

运行时常量池,存储编译器生成的常量和引用

2.2 堆区

存放对象实例和数组, new出来的对象都存放在此

是GC机制最重要的区域

进行分代管理

 新生代(Youn Generation):大致分为Eden区和Survivor区,Survivor区又分为大小相同的两部分:FromSpace和ToSpace。新建的对象都是从新生代分配内存(大对象会直接在老年代分配),Eden区不足的时候,会把存活的对象转移到Survivor区。当新生代进行垃圾回收时会出发Minor GC(复制算法也称作Youn GC)。在执行垃圾回收之后,仍没有足够的内存分配,也不能再扩展,将会抛出OutOfMemoryError:Java Heap Space异常。

       老年代(Old Generation):旧生代用于存放新生代多次回收依然存活的对象,如缓存对象。当旧生代满了的时候就需要对旧生代进行回收,旧生代的垃圾回收称作Major GC(标记-压缩算法也称作Full GC)。

       持久代(Permanent Generation):在Sun 的JVM中就是方法区的意思,尽管大多数JVM没有这一代。

以下三个是线程同步,生命周期随着线程销毁而销毁,不需要回收

2.3 本地方法栈

2.4 虚拟机栈

2.5 程序计数器

3. 算法

两种查找算法

3.1. 引用计数法

对象被引用+1,失去引用-1 ,为0时就可以回收,但是相互引用的对象不能处理

3.2. 根搜索算法

从GC Roots的根节点出发,向下搜索,如果一个对象不能达到GC Roots的时候,说明该对象不再被引用,可以被回收,就解决了引用计数算法的缺陷。

3.3 强引用、软引用、弱引用、虚引用。

       强引用:new出来的对象都是强引用,GC无论如何都不会回收,即使抛出OOM异常。

       软引用:只有当JVM内存不足时才会被回收。

       弱引用:只要GC,就会立马回收,不管内存是否充足。

       虚引用:可以忽略不计,JVM完全不会在乎虚引用,唯一的作用就是做一些跟踪记录,辅助finalize函数的使用。

GC算法

3.3 复制

从根集合进行扫描,将存活的对象移动到另一块空闲的区域,存活较少时算法效率高,但是成本时一块的空闲区域和对象移动

3.4 标记-清除

从根集合开始扫描,存活的进行标记,再扫描整个空间,未被标记的清除,扫描耗时

3.5 标记-压缩

与标记清除类似,再加上整理碎片,进行移动。

4. 垃圾收集器

4.1 串行收集器

4.2 并行收集器

4.3 CMS收集器

4.4 G1收集器

 

<think>嗯,用户想了解Java内存模型的分区以及垃圾回收机制相关算法。首先,我需要回忆一下Java内存模型的结构。根据引用[4],堆是所有线程共享的内存区域,几乎所有的对象实例数组都在这里分配。堆又分为新生代老年代,而新生代还有Eden、From SurvivorTo Survivor区。然后,除了堆之外,还有方法区(元空间)、栈程序计数器等,但用户可能更关注堆的分区,因为GC主要在这里进行。 接下来是垃圾回收机制。用户提到GC算法,根据引用[2][3],分代收集算法是关键。年轻代使用复制算法,因为对象生命周期短,频繁回收,复制算法适合这种场景。而老年代用标记-清除或标记-压缩,因为对象存活时间长,减少内存碎片很重要。需要解释这些算法的工作原理,以及它们在不同分代中的应用。 可能还需要提到不同的垃圾收集器,比如Serial、Parallel、CMS、G1等,但引用中提到的信息有限,需要根据现有的引用来组织内容。例如,引用[2]提到了分代收集算法的具体实现,年轻代的minorGC老年代的majorGC,可以结合代码示例来说明。 用户的问题可能涉及到GC如何判断对象是否为垃圾,引用[5]提到垃圾判断算法,比如引用计数法可达性分析。需要详细说明这两种方法,以及Java主要使用哪种(可达性分析)。 另外,引用[1]提到GC降低了程序员门槛,说明GC的重要性。需要强调自动内存管理的好处,比如避免内存泄漏简化开发。 现在要组织这些信息,分点回答内存分区、GC机制GC算法种类,同时引用相关文献。需要确保每个部分都清晰,引用正确,比如分代的部分引用[2][3][4],垃圾判断引用[5],分代收集算法引用[2][3]。 可能用户还需要了解各分代的具体GC过程,比如对象先在Eden分配,空间不足时触发Minor GC,存活对象移到Survivor,多次存活后进入老年代。老年代空间不足时触发Full GC。这些细节需要结合引用内容来阐述。 最后,生成相关问题时要围绕内存分区、GC算法、收集器类型、性能调优等方面,确保问题覆盖用户可能感兴趣的后续知识点。</think>### Java内存模型分区与垃圾回收机制详解 --- #### 一、Java内存模型分区 Java堆内存主要分为以下几个区域(基于分代策略): 1. **新生代(Young Generation)** - **Eden区**:对象首次分配内存的区域,当Eden区满时触发$Minor GC$[^5]。 - **Survivor区**(From/To):存放经过一次$Minor GC$后存活的对象,采用复制算法避免内存碎片[^2][^4]。 $$ \text{新生代内存布局:Eden (80\%) + From Survivor (10\%) + To Survivor (10\%)} $$ 2. **老年代(Old Generation)** - 存放长期存活的对象(例如多次$Minor GC$后仍存活的对象),使用标记-清除或标记-压缩算法[^3][^4]。 3. **元空间(Metaspace,Java 8+)** - 替代永久代,存储类元数据,由本地内存管理[^2]。 --- #### 二、垃圾回收(GC机制 1. **垃圾判断算法** - **引用计数法**:通过对象被引用次数判断,但无法解决循环引用问题。 - **可达性分析**(Java主流方法):从GC Roots(如栈帧变量、静态变量)出发,标记不可达对象为垃圾[^5]。 2. **分代收集策略** - **年轻代**:使用**复制算法**,将存活对象从EdenFrom Survivor复制到To Survivor。 - **老年代**:使用**标记-清除**(产生碎片)或**标记-压缩**(整理内存)算法。 --- #### 三、GC算法种类 | 算法类型 | 原理 | 适用场景 | |----------------|--------------------------------------|-----------------| | **复制算法** | 将存活对象复制到新内存区域 | 年轻代(Survivor区) | | **标记-清除** | 标记垃圾对象后直接回收 | 老年代(低频率GC) | | **标记-压缩** | 标记后整理存活对象消除碎片 | 老年代(高内存要求) | | **分代收集** | 结合上述算法按代优化 | JVM全局策略 | --- #### 四、典型GC流程示例 1. **对象分配** - 大多数对象在Eden区分配,若Eden满则触发$Minor GC$。 2. **晋升老年代** - 对象在Survivor区每熬过一次$Minor GC$年龄+1,达到阈值(默认15)后进入老年代。 3. **Full GC触发条件** - 老年代空间不足、元空间不足或显式调用`System.gc()`。 ```java // 分代GC示例(伪代码) class GenerationalGC { void minorGC() { copy(youngGeneration.fromSpace, youngGeneration.toSpace); // 复制算法[^2] } void majorGC() { markCompact(oldGeneration); // 标记-压缩算法[^2] } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值