java自动垃圾回收机制

前言:相比C++,java做的一大改进是将复杂的内存管理抽离出来交给jvm去处理,让码农不再时刻盯着内存泄漏的问题,可以更专注于业务逻辑的开发。

java的GC机制是和其内存模型相关联的,而GC的核心内存区域是内存中的堆区。

java堆区按对象的存活时间被分为了年轻代(eden区+s0区+s1区)和老年代(tentired区),java堆的按代区分其实是为了其垃圾回收的分代收集机制打开了方便之门。java的GC收集器会在不同的分代上使用不同的垃圾收集策略。

GC其实主要需要解决两个问题:哪些是垃圾?如何清理垃圾?

在解决这两个问题上涉及到下面的方法论:

1.垃圾对象判定方法

引用计数法:在C++的智能指针中使用了这种方式去做内存的自动回收。即在对象生成时维护一个对该对象引用次数的计数器,对象初次生成时计数器值为1,每增加一个到该对象的引用,计数器加1,每减少一个引用(如引用变量赋值null,或引用变量离开作用域),计数器减1,计数器为零时,对象内存会被自动回收。该方法的问题是存在内存泄漏的隐患,如对象相互引用、循环引用等情况

相互引用:

public class ReferenceCountingGc {
    Object instance = null;
	public static void main(String[] args) {
		ReferenceCountingGc objA = new ReferenceCountingGc();
		ReferenceCountingGc objB = new ReferenceCountingGc();
		objA.instance = objB;
		objB.instance = objA;
		objA = null;
		objB = null;

	}
}

  例子中两个new出来的对象ReferenceCountingGc由于通过内部的变量instance引用着对方,两个对象的引用计数都为1。但是在程序中已经不会再用到这两个对象,这样就出现了内存泄漏。

循环引用:

public class ReferenceCountingGc {
    Object instance = null;
	public static void main(String[] args) {
		ReferenceCountingGc objA = new ReferenceCountingGc();
		objA.instance = objA ;
		objA = null;
	}
}

  例子中new出来的对象ReferenceCountingGc通过内部的变量instance引用自身对象,最后引用计数也为1。最后该对象内存也出现泄漏

基于引用计数法出现的问题,目前的jvm都不采用这种方式,而是使用下面的可达性分析的方式

可达性分析法:

通过一系列的称为 “GC Roots” 的对象作为起点,搜索这些节点引用的对象,以及这些引用对象内部属性引用的对象,相当于从一个树形结构的根部进行遍历。节点所走过的路径称为引用链,当一个对象处于引用链上,就被判断为可用对象。其它的对象就是要被清理的无用对象。目前jvm都是采用这种方式进行垃圾对象的判断的。

补充说明:引用计数和可达性分析我觉得有点像黑名单和白名单两种思路。引用计数的方式采用了黑名单的方式来处理问题,把计数为零相当于一个黑名单条件,满足条件的对象是需要清理的垃圾对象,处于黑名单中。可达性分析法是将处于引用链的对象加入白名单,白名单外的对象被清理。我们在进行数据过滤时经常会用到黑白名单的思路,白名单由于对有效数据的限制条件更严格,这种过滤方式往往也更精确。

2.垃圾对象清理方法

java在GC过程中会依据年轻代和永久代中对象的不同特点采用不同的对象清理方式,即所谓的分代收集策略,其中涉及到的方法有下面几种。

2.1 标记-清除算法:

通过可达性分析方式找到所以需要回收的对象,并进行标记,在标记完成后统一回收所有被标记的对象。

主要问题是容易参数内存碎片。

2.2 复制算法

它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。

目前java堆中的年轻代在进行young GC时采用的这种方式,其中划分出的两块内存s0区和s1区就是这样用的,每次GC都会切换身份,一个存放存活对象,一个存放新生对象。

2.3 标记-整理算法

标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。以此避免内存碎片。

java堆的老年代一般采用这种方式进行GC

前面讲的都是jvm在GC过程中在寻找垃圾和清理垃圾方面使用到的方法论,那么jvm具体是如何执行GC的呢?

jvm其实是通过一个叫垃圾收集器的东西进行GC的,垃圾收集器在jvm启动后的外部体现就是一个或多个运行中的线程(针对单线程收集器或多线程收集器)。收集器线程会在整个jvm生命周期内判断需要GC的时间点并执行GC的逻辑,而这些逻辑的理论基础就是上面提到的那些方法论。

目前jvm中使用到的垃圾收集器主要有下面几种,通过java命令启动应用的时候jvm会使用默认的搜集器,根据实际应用场景也可以在启动应用时,通过命令行参数设置使用哪张搜集器

Serial 收集器:单线程,新生代采用复制算法,老年代采用标记-整理算法。
ParNew 收集器:Serial 收集器的多线程版本,新生代采用复制算法,老年代采用标记-整理算法。
Parallel Scavenge 收集器:多线程,新生代采用复制算法,老年代采用标记-整理算法。
Serial Old 收集器:Serial 收集器的老年代版本,单线程
Parallel Old 收集器:Parallel Scavenge 收集器的老年代版本,多线程
CMS 收集器:多线程,并发收集,标记-清除
G1 收集器:多线程,并发收集,复制加标记整理

原文地址:https://www.cnblogs.com/imyhb/p/11228299.html

时间: 2024-10-16 08:17:40

java自动垃圾回收机制的相关文章

Java的垃圾回收机制(转载)

引用自 <http://lemote.blog.163.com/blog/static/1748395072013111641050934/> 引自文章:<http://blog.csdn.net/zsuguangh/article/details/6429592>    Java的垃圾回收机制是Java虚拟机提供的能力,用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的内存空间.需要注意的是:垃圾回收回收的是无任何引用的对象占据的内存空间而不是对象本身,很多人来我公司面试

面试官,不要再问我“Java GC垃圾回收机制”了

Java GC垃圾回收几乎是面试必问的JVM问题之一,本篇文章带领大家了解Java GC的底层原理,图文并茂,突破学习及面试瓶颈. 楔子-JVM内存结构补充 在上篇<JVM之内存结构详解>中有些内容我们没有讲,本篇结合垃圾回收机制来一起学习.还记得JVM中堆的结构图吗? 图中展示了堆中三个区域:Eden.From Survivor.To Survivor.从图中可以也可以看到它们的大小比例,准确来说是:8:1:1.为什么要这样设计呢,本篇文章后续会给出解答,还是根据垃圾回收的具体情况来设计的.

Java的垃圾回收机制笔记

Java的垃圾回收机制笔记 java垃圾回收的意义 确保不再被引用的对象的内存空间被回收. 确保被引用的对象的内存不被错误回收. 再分配内存. java垃圾回收的常用方法 引用计数收集器 堆中的每个对象(不是对象的引用)都有一个引用计数.当一个对象被创建时,给该对象分配一个变量,该变量计数设置设置为1.当任何其他变量被赋值为这个对象的引用,计数加1(a=b,则b引用的对象计数+1),但当一个对象的某个引用超过生命周期或者被设置为一个新值的时候,引用的计数减1(a=c,则a不再指向b指向的对象,而

java的垃圾回收机制的特点

浅谈java的垃圾回收机制的特点: 1.垃圾回收机制的目标是回收无用对象的内存空间(记住:不是对象),这些内存空间是JVM堆内存的内存空间.垃圾回收只回收内存资源,对于那些物理资源,如数据库连接,Socket,I/O流等资源无能无能为力,我们要自己关闭回收. 2.为了加快垃圾回收机制回收那些无用对象所占的内存空间,我们可以讲对象的引用变量置于null(记住:置于null后,垃圾回收机制不会立即执行的). 3.垃圾回收机制的潜在缺点它的开销会影响性能.Java虚拟机必须跟踪程序中有用的对象才可以确

Java的垃圾回收机制

以前很少关注内存的问题,基本没有关注,这方面的小白,原因在于自己都是写的自我娱乐的小程序,不关注性能,不是提供服务.而企业级别的应用在程序稳健性方面的要求大大提高,因此要考虑更多的问题.对于大公司来说,为了应对各种情况,服务器资源肯定充足,但是由于应用很多,那么我们要尽可能的节省资源,对于Java程序,内存资源相当宝贵,那么理解java里面怎么做垃圾回收,是很重要的. 我阅读的参考主要是两个内容[1,2],但还没有做具体的实践,也没有切身体会,只能纸上谈兵了. 那么首先要介绍Java里面的内存分

记录Java的垃圾回收机制和几种引用

一.Java的垃圾回收机制 Java的垃圾回收机制(java garbage collection)是Java虚拟机提供的能力,用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的堆内存空间. 注意粗体字的地方,java的垃圾回收线程是优先级比较低的线程,什么时候进行垃圾回收难以确定.当某些对象被标记为垃圾对象后,等垃圾回收线程运行时,就会将这些对象回收(确切的说应该是回收这些对象所占的堆内存空间). 二.什么样的对象会被标记成垃圾对象呢? 一般来说,所有指向对象的引用都已失效,不可能再有

自动垃圾回收机制(ARC)

手动内存管理(MRC)带来的问题: 1.0 由于开发者疏漏或不能正确的释放内存而导致的内存泄漏,从而引起程序的崩溃 2.0 由于指针的到处传递而无法确定何时可以释放该指针所 指向的内存块.假如代码中某个位置释放了内存,而另一些地方还在使用指向这块内存的指针, 那么这些指针就变成了所谓的“野指针”(wild pointer)或者“悬空指针”(dangling pointer),对 这些指针进行的任何读写操作都会导致不可预料的后果. 3.0 著名的内存检查工具,比如Rational Purify.C

java有自动垃圾回收机制

当垃圾收集器判断已经没有任何引用指向对象的时候,会调用对象的finalize方法来释放对象占据的内存空间~ java中垃圾回收以前听老师讲好像是内存满了他才去做一次整体垃圾回收,在回收垃圾的同时会调用finalize方法.你在构造一个类时可以构造一个类时覆盖他的finalize方法以便于该类在被垃圾回收时执行一些代码,比如释放资源. 1.JVM的gc概述 gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm

java JVM垃圾回收机制

Java语言出来之前,大家都在拼命的写C或者C++的程序,而此时存在一个很大的矛盾,C++等语言创建对象要不断的去开辟空间,不用的时候有需要不断的去释放控件,既要写构造函数,又要写析构函数,很多时候都在重复的allocated,然后不停的~析构.于是,有人就提出,能不能写一段程序在实现这块功能,每次创建,释放控件的时候复用这段代码,而无需重复的书写呢? 1960年 基于MIT的Lisp首先提出了垃圾回收的概念,用于处理C语言等不停的析构操作,而这时Java还没有出世呢!所以实际上GC并不是Jav