1、引用计数收集器
(Reference Counting)
引用计数是垃圾收集的早期策略。在这种方法中,堆中每一个对象都有一个引用计数。一个对象被创建了,并且指向该对象的引用被分配给一个变量,这个对象的引用计数被置为1。当任何其他变量被赋值为对这个对象的引用时,计数加1。当一个对象的引用超过了生存期或者被设置一个新的值时,对象的引用计数减1。任何引用计数为0的对象可以被当作垃圾收集。当一个对象被垃圾收集的时候,它引用的任何对象计数值减1。
在这种方法中,一个对象被垃圾收集后可能导致后续其他对象的垃圾收集行动。
这种方法的好处是,引用计数收集器可以很快地执行,交织在程序的运行之中。这个特性对于程序不能被长时间打断的实时环境很有利。坏处就是,引用计数无法检测出循环(即两个或者更多的对象互相引用)。
循环的例子如,父对象有一个对子对象的引用,子对象又反过来引用父对象。这些对象永远都不可能计数为0,就算它们已经无法被执行程序的根对象可触及。还有一个坏处就是,每次引用计数的增加或者减少都带来额外开销。
因为引用计数方法固有的缺陷,这种技术现在已经不为人所接受。现实生活中所遇到的Java虚拟机更有可能在垃圾收集堆中使用追踪算法。
2、标记-清除收集器(Mark-Sweep)或追踪回收器(
Tracing Collector)
跟踪收集器追踪从根结点开始的对象引用图。在追踪过程中遇到的对象以某种方式打上标记。
总的来说,要么在对象本身设置标记,要么用一个独立的位图来设置标记。当追踪结束时,未被标记的对象就知道是无法触及的,从而可以被收集。
基本的追踪算法被称作“标记并清除”。这个名字指出垃圾收集过程的两个阶段。在标记阶段,垃圾收集器遍历引用树,标记每一个遇到的对象。在清除阶段,未被标记的对象被释放了,使用的内存被返回到正在执行的程序。在Java虚拟机中,清除步骤必须包括对象的终结。下面的图示显示了这种收集器的收集过程:
垃圾回收器回收了堆中的对象之后,自然会在堆内存中遗留下一些内存空闲的间隙,下面就是完成上图所示的标记-清除垃圾回收之后的堆内存变化,我们能很清楚的看到这一点。
下面我们就要讨论如何对付这些回收对象后产生的内存碎块的垃圾回收器。
3、基于标记-清除的压缩收集器
压缩方法把活动的对象越过空闲区滑动到堆的一端,在这个过程中,堆的另一端出现一个大的连续空闲区。所有被移动的对象的引用也被更新,指向新的位置。
更新被移动的对象的引用有时候通过一个间接对象引用层可以变得更简单。不直接引用堆中的对象,对象的引用实际上指向一个对象句柄表。对象句柄才指向堆中对象的实际位置。当对象被移动了,只有这个句柄需要被更新为新位置。所有的程序中对这个对象的引用仍然指向这个具有新值的句柄,而句柄本身没有移动。这种方法简化了消除堆碎块的工作,但是每一次对象访问都带来了性能损失。
4、拷贝收集器
一般的拷贝算法被称为“停止并拷贝”、,在这个方案中,堆被分为两个区域,任何时候都只使用其中的一个区域。对象在同一个区域中分配,直到这个区域被耗尽。此时,程序执行被中止、堆被遍历,遍历时遇到的活动对象被拷贝到另外一个区域。当停止和拷贝过程结束时。程序恢复执行。内存将从新的堆区域中分配,直到它也被用尽。那时程序将再次中止。遍历堆、活动对象又被拷贝回原来的区域‘这种方一法带来的代价就是,对于指定大小的堆来说需要两倍大小的内存,因为任何时候都只能使用其中的一半。下图就是一个停止并拷贝的过程:
5、按代收集器(Generational Collector)
简单的停止并拷贝收集器的缺点是每一次收集时,所有的活动对象都必须被拷贝。大部分语言的大多数程序都有以下特点,如果我们全面考虑这些,拷贝算法的这个缺点足可以被改进的。
(1) 大多数程序创建的大部分对象都具有很短的生命期。
(2)大多数程序都创建一些具有非常长生命周期的对象。
简单的拷贝收集器浪费效率的一个上要原因就是、它们每次都把这些生命周期很长的对象来回拷贝,消耗大量时间。
按代收集的收集器通过把对象按照寿命来分组解决这个效率低下的问题,更多地收集那些短暂出现的年幼对象,而非寿命较长的对象。在这种方法里,堆被划分成两个或者更多的子堆,
每一个子堆为一“代”对象服务。最年幼的那一代进行最频繁的垃圾收集。因为大多数对象都是短促出现的,只有很小部分的年幼对象可以在它们经历第一次收集后还存活。如果一个最年幼的对象经历了好几次垃圾收集后仍然存活,那么这个对象就成长为寿命更高的一代:它被转移到另外一个子堆中去。年龄更高的每一代的收集都没有年径的那一代来得频繁。每当对象在它所属的年龄层(代)中变得成熟(逃过了多次垃圾收集)之后,它们就被转移到更高的年龄层中去。
按代进行的收集技术除了可以应用于拷贝算法,也可以应用于标记并清除算法。不管在哪种情况下,把堆按照对象年龄层分解都可以提高最基本的垃级收集算法的性能。
总结
引用计数收集器
基本上已经不被使用了。
标记-清除收集器
是目前寻找垃圾对象的主流策略,但是它对回收后产生的内存碎片却无能为力,因此我们必须采用一些合并空闲内存的算法,这就产生了基于标记-清除的
压缩收集器
和
拷贝收集器
。而基于性能原因,拷贝收集器是比较受欢迎的。但是它有一个比较大的弱点:对于寿命较长的对象会不停的拷贝,这就付出了不必要的代价。因此,
按代收集器
的出现
改进了这一性能。而我们的JDK中的JVM就采用了按代收集策略。
垃圾回收的若干问题
(1) 垃圾回收从哪里开始??
上面说到的“引用计数”法,通过统计控制生成对象和删除对象时的引用数来判断。垃圾回收程序收集计数为0的对象即可。但是这种方法无法解决循环引用。所
以,后来实现的垃圾判断算法中,都是从程序运行的根节点出发,遍历整个对象引用,查找存活的对象。那么在这种方式的实现中,垃圾回收从哪儿开始的呢
?
即,从哪儿开始查找哪些对象是正在被当前系统使用的。上面分析的堆和栈的区别,其中栈是真正进行程序执行地方,所以要获取哪些对象正在被使用,则需要从
Java栈开始。同时,一个栈是与一个线程对应的,因此,如果有多个线程的话,则必须对这些线程对应的所有的栈进行检查。
同时,除了栈外,还有系统运行时的寄存器等,也是存储程序运行数据的。这样,以栈或寄存器中的引用为起点,我们可以找到堆中的对象,又从这些对象找到对
堆中其他对象的引用,这种引用逐步扩展,最终以null引用或者基本类型结束,这样就形成了一颗以Java栈中引用所对应的对象为根节点的一颗对象树,如
果栈中有多个引用,则最终会形成多颗对象树。在这些对象树上的对象,都是当前系统运行所需要的对象,不能被垃圾回收。而其他剩余对象,则可以视为无法被引
用到的对象,可以被当做垃圾进行回收。
因此,垃圾回收的起点是一些根对象(java栈, 静态变量, 寄存器...)
。而最简单的Java栈就是Java程序执行的main函数。这种回收方式,也是上面提到的“标记-清除”的回收方式。
(2) 如何处理碎片??
由于不同Java对象存活时间是不一定的,因此,在程序运行一段时间以后,如果不进行内存整理,就会出现零散的内存碎片。碎片最直接的问题就是会导致无法
分配大块的内存空间,以及程序运行效率降低。所以,在上面提到的基本垃圾回收算法中,基于标记-清除的压缩收集器和拷贝收集器
,都可以解决碎片的问题。
(3) 如何解决同时存在的对象创建和对象回收问题??
垃圾回收线程是回收内存的,而程序运行线程则是消耗(或分配)内存的,一个回收内存,一个分配内存
,从这点看,两者是矛盾的。因此,在现有的垃圾回收方式中,要进行垃圾回收前,一般都需要暂停整个应用(即:暂停内存的分配),然后进行垃圾回收,回收完成后再继续应用。这种实现方式是最直接,而且最有效的解决二者矛盾的方式。
但是这种方式有一个很明显的弊端,就是当堆空间持续增大时,垃圾回收的时间也将会相应的持续增大,对应应用暂停的时间也会相应的增大
。
一些对相应时间要求很高的应用,比如最大暂停时间要求是几百毫秒,那么当堆空间大于几个G时,就很有可能超过这个限制,在这种情况下,垃圾回收将会成为系统运行的一个瓶颈。为解决这种矛盾,有了并发垃圾回收算法
,使用这种算法,垃圾回收线程与程序运行线程同时运行。在这种方式下,解决了暂停的问题,但是因为需要在新生成对象的同时又要回收对象,算法复杂性会大大增加,系统的处理能力也会相应降低,同时,“碎片”问题将会比较难解决。
分享到:
相关推荐
全面概述jvm垃圾回收机制的功能、各部分组成及各部分算法实现
### JVM工作原理及垃圾回收机制详解 #### 一、JVM概述及原理 **1.1 JVM概述** Java Virtual Machine (JVM),即Java虚拟机,是一种虚构的计算机,在实际的计算机硬件上仿真模拟出的一套完整的计算机系统,用于执行...
本文将详细探讨JVM的发展历程以及内存管理中的垃圾回收机制。 一、JVM的历史发展 1. **早期阶段**:1995年,Sun Microsystems发布了Java的第一个版本,JVM作为其核心组成部分,主要应用于嵌入式设备和网络应用。初...
gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存。java语言并不要求jvm有gc,也没有规定gc如何工作。不过常用的jvm都有gc,而且大多数gc都使用类似的算法管理内存和执行收集操作。 在充分理解了...
### 垃圾回收机制详解 #### 一、引言 在现代软件开发过程中,内存管理是确保程序高效稳定运行的关键因素之一。垃圾回收(Garbage Collection,简称GC)作为自动内存管理的一部分,在Java等高级语言中扮演着至关...
Java的垃圾回收机制(Garbage Collection, GC)是Java虚拟机(JVM)的一项核心功能,用于自动管理程序运行时产生的无用对象,以回收其占用的内存资源。 1. **垃圾回收器的工作原理**:垃圾回收器定期检查内存中不再...
### JAVA垃圾回收个人总结 #### 一、垃圾回收(GC)概述 垃圾回收(Garbage Collection,简称GC)是Java虚拟机(JVM)提供的一种自动内存管理机制,...随着Java虚拟机技术的发展,未来的垃圾回收机制将会更加高效、智能。
理解这一内存模型对于理解JVM的内存管理和垃圾回收机制是必要的。 5. JVM调优的重点 JVM调优通常关注垃圾回收(GC)算法的选择和调优,以及堆内存的大小设置。调优过程可能涉及调整JVM启动参数,如堆的初始大小和...
【垃圾回收机制】 - 年轻代的Eden区和两个Survivor区按8:1:1的比例划分。 - 新对象先放在Eden区,满时触发Minor GC,存活对象复制到Survivor区。 - 若Survivor区无法容纳,对象直接进入老年代。 - 对象经过多次...
- 除了基本的垃圾回收机制之外,现代的JVM还支持一些高级特性,比如对象局部化(Object Localization)、内存池管理等,这些特性可以帮助进一步优化内存使用效率。 #### 四、总结 通过对Java语言回收机制的深入...
### 详细介绍Java垃圾回收...综上所述,理解Java垃圾回收机制的基本原理及其工作方式对于优化Java应用的性能至关重要。开发者可以通过合理选择垃圾回收器以及调整相关的参数来平衡内存使用效率与系统性能之间的关系。
- **垃圾回收机制**:JVM通过自动垃圾回收机制来管理对象的生命周期,了解其工作原理有助于优化内存使用。 - **类加载机制**:类加载是JVM启动后的一个重要环节,理解类加载过程对于解决类加载问题具有重要意义。 ...
【Java的垃圾回收机制概述】 Java的垃圾回收(Garbage Collection,简称GC)是其内存管理的核心机制,它自动管理程序中的对象生命周期,负责回收不再使用的对象所占用的内存空间,以防止内存泄漏。GC是Java语言的一...
垃圾回收机制分为两种:标记-清除算法和标记-压缩算法。标记-清除算法将无用对象标记为可回收,然后清除这些对象。标记-压缩算法将无用对象标记为可回收,然后将存活对象压缩到堆的其中一端。 JVM的性能优化 JVM的...
包括JVM执行过程、虚拟机类加载机制、运行时数据区、GC、类加载器、内存分配与回收策略等,全套视频加资料高清无密码 第1讲 说在前面的话 免费 00:05:07 第2讲 整个部分要讲的内容说明 免费 00:06:58 第3讲...
**1.1 垃圾回收机制概述** JVM(Java虚拟机)的垃圾回收机制(Garbage Collection, GC)是自动内存管理的核心部分。它负责识别并回收不再使用的对象所占用的内存空间,从而避免内存泄漏问题。GC主要关注于及时释放...
总结,Java与JVM的关系密切,Java的跨平台特性得益于JVM,而JVM的内存管理和垃圾收集则为Java程序的稳定运行提供了保障。在后端开发中,Java以其强大的功能和成熟的生态系统,成为了不可或缺的工具。
### JVM调优文档:垃圾收集(GC)与性能优化 #### 概述 Java虚拟机(JVM)作为运行Java程序的核心组件,其性能直接影响着应用程序的运行效率和稳定性。在JVM中,垃圾收集(GC)是自动管理内存的重要机制之一。本文...
JVM的主要职责包括加载类文件(class loader)、执行字节码(execution engine)以及管理内存(包括垃圾回收机制)。以下是对JVM的详细讲解。 ### 1. Java概述 1.1 **Java定义**:Java是一种高级编程语言,由Sun ...
理解JVM内存结构和内存分配机制对于避免内存溢出(OutOfMemoryError)、提升程序性能、减少垃圾回收开销至关重要。开发者应关注内存配置、对象生命周期管理以及适当的垃圾回收策略,以优化应用程序的性能和稳定性。