垃圾收集器(一)

GC需要完成的3件事情:

1.哪些内存需要回收?

2.什么时候回收?

3.如何回收?

哪些内存需要回收?

对于程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程而灭,栈帧随方法的进入和退出执行入栈和出栈的操作。每一个栈帧分配多少内存基本上在类结构确定下来时就已知(运行期JIT编译器会进行一些优化,但大体上认为是编译期可知),因此这3个区域的内存分配和回收具备确定性,因为方法结束或者线程结束,内存就跟着被回收了。

而Java堆和方法区则不一样。只有在运行期才能知道会创建哪些对象,这部分内存的分配和回收都是动态的,垃圾收集器关注的是这部分内存。

什么时候回收?

堆存放着几乎所有的对象实例,如何确定对象是否有必要继续存在。

可达性分析算法,基本思路是通过一系列称为“GC Roots”的对象作为起始点,从这些节点向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连(GC Roots到这个对象不可达),则证明此对象不可用。

object5、object6、object7虽然互有关联,但它们到GC Roots是不可达的,所以将被判定为可回收的对象。

可作为GC Roots的对象

1.虚拟机栈(栈帧中的本地变量表)中引用的对象

2.方法区中类静态属性引用的对象

3.方法区常量引用的对象

4.本地方法栈中JNI(Native方法)引用的对象

JDK1.2之后,引用概念被扩充了,以便可以描述更复杂的对象,比如当内存空间还足够时,则继续保留在内存之中,如果内存空间在进行垃圾收集后还是非常紧张,则可以抛弃这些对象(缓存功能)。

1.强引用:类似Object o = new Object()

2.软引用:描述有用但并非必须的对象,在系统即将发生内存溢出的时候,把这些对象列进回收范围,进行第二次回收,如果这些回收还没有足够内存,才抛出内存溢出异常

3.弱引用:描述非必须对象,强度比软引用弱一些,只能生存到下一次垃圾收集发生之前,无论内存是否足够,都会被回收掉

4.虚引用:最弱的引用关系,为一个对象设置虚引用关联的唯一目的是能在这个对象被垃圾回收时收到一个系统通知

回收方法区:

回收的目标:废弃常量和无用的类。

没有任何引用的常量为废弃常量

判断无用的类满足的条件:

1.该类的所有实例都已经被回收,也就是Java堆中不存在该类的任何实例

2.加载该类的ClassLoader已经被回收

3.该类对应的java.lang.Class对象没有在任何地方被引用,无法再任何地方通过反射访问该类

垃圾收集算法:

1.标记-清除(Mark-Sweep)

分为标记和清除两个阶段,首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

不足之处:效率问题,标记和清除两个过程的效率都不高;空间问题,标记清除之后产生大量不连续的内存碎片,空间碎片太多导致以后分配较大对象,无法找到足够的连续空间而不得不触发另一次垃圾收集动作。

2.复制算法(Copying)

将可用内存容量划分为大小相等的两块,每次只使用其中一块,当这一块的内存用完了,就将还存活着的对象复制到另一块上,然后再把已使用过的内存一次清理掉。使得每次都是对整个半区进行内存回收,不用考虑内存碎片问题,只要移动堆顶指针,按序分配即可,实现简单,运行高效。

缺点:内存缩小为原来的一半,浪费大量内存空间。

商用虚拟机都采用这种算法回收新生代,IBM专门研究表明,新生代的对象98%是“朝生夕死”,所以不需要按1:1的比例来划分内存空间,而是将内存分为一块较大的Eden空间,和两块较小的Survivor空间,每次使用Eden和其中一块Survivor,当回收时,将Eden和Survivor中还存活的对象一次性复制到另一块Survivor空间,最后清理掉Eden和刚用过的Survivor空间,HotSpot默认Eden和Survivor的大小比例是8:1,只有10%的内存被“浪费”。没有办法保证每次回收只有不多于10%的对象存活,当Survivor空间不够时,需要依赖其他内存(老年代)进行分配担保。

3.标记-整理算法(Mark-Compact)

复制收集算法在对象存活率较高时要进行较多的复制操作,效率会变低,如果不想浪费50%空间,就需要额外的空间进行分配担保,以应对被使用的内存中所有对象都100%存活的情况,所以老年代一般不使用这种算法。而是使用标记-整理算法。

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

4.分代收集算法

只是根据对象存活周期的不同将内存划分为几块,一般分为新生代和老年代,这样可以根据年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集都有大批对象死去,只有少量存活,就选用复制算法,而老年代对象存活率高,采用标记-清理或者标记-整理算法进行回收。

时间: 2024-10-26 00:26:55

垃圾收集器(一)的相关文章

垃圾收集器与内存分配策略

①对于java虚拟机来说,垃圾收集器主要关注的内存区域是 堆和方法区. ②垃圾收集器就是要收集那些已经“死了”的对象.如果判断一个对象是否存活? 对象引用计数法 对象引用增加一个,那么相应的计数器加1,否则,减1. 优点:实现简单 缺点:不能处理对象间的循环引用.a引用b,b同时引用a. 可达性分析 如果节点到root节点可达,则证明是存活的:否则,已死.所以对于下图的o5,o6,o7虽然他们是循环引用的,但是到root节点无可达,所以已死可清除. ③垃圾回收器对于不同类型引用的回收规则 强引用

垃圾收集器

垃圾收集器 引用计数器: 从gc日志可以看出是回收了,java虚假没有选用引用计数器算法管理内存 可达性分析算法 ?线程池中线程是维持一个数量还是,用已经有的线程? 回收方法区 垃圾收集器 垃圾收集器根据应用场景和内存回收范围来选择.根据新生代.老年代,高性能服务器.客户端,计算密集场景.高响应场景.选择不同的收集器. 单线程收集器 单线程收集器,是使用单线程去完成垃圾回收工作.在垃圾收集的同时要暂停其它所有的工作线程,直到收集结束.即"Stop The World". 多线程收集器

看图说说JVM老年代垃圾收集器

注:G1垃圾收集器是目前最前沿的GC收集器,未来将取代CMS垃圾收集器,可以作为整个Heap的收集器使用,不限于老年代!!!

JVM垃圾回收机制总结(5) :JDK垃圾收集器的配置命令

以下配置主要针对分代垃圾回收算法而言. 堆大小设置 年轻代的设置很关键 JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理内存限制.32位系统下,一般限制在1.5G~2G:64为操作系统对内存无限制.在Windows Server 2003 系统,3.5G物理内存,JDK5.0下测试,最大可设置为1478m. 典型设置: java -Xmx3550m -Xms3550m -Xmn2g –Xss128k -Xmx3550

Java虚拟机垃圾收集器

垃圾收集器用到的垃圾收集算法 标记-清除(Mark-Sweep)算法: 首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象.它主要有两个缺点:一个是效率问题,标记和清楚过程的效率都不高:另外一个是空间问题,标记清楚后会产生大量不连续的内存碎片,空间碎片太多可能会导致,当程序在以后的运行过程中需要分配较大对象时无法找到足够连续的内存空间而不得不提前出发另一次垃圾收集动作. 执行过程如下图所示: 复制算法: 它将可用内存按容量划分为大小相等的两块,每次只是用其中一块.当这一块的内存用

垃圾收集器与内存分配策略(一)

1.判断对象是否存活 a.计数器算法  算法描述:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值加1:当引用失效时,计数器值减1:任何时刻计数器为0的对象就是不可能再被使用的. 该算法实现简单,效率也很高,但是Java虚拟机中没有使用计数器算法来管理内存,主要原因就是它很难解决对象之间相互循环引用的问题.  b.可达性分析算法 算法描述:通过一系列的称为"GC Roots"的对象作为起点,从这些节点开始向下进行搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots

GC算法 垃圾收集器

GC算法 垃圾收集器 参考:http://www.cnblogs.com/ityouknow/p/5614961.html 概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本地方法栈都是随线程而生随线程而灭,栈帧随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理,因此,我们的内存垃圾回收主要集中于 java 堆和方法区中,在程序运行期间,这部分

深入理解JVM之四:详解垃圾收集器

前言 前面已经对垃圾收集算法有了较为详细的介绍,这里我们将对JVM中具体的垃圾回收器进行介绍,在虚拟机规范中并没有对垃圾回收器如何实现具体介绍,因此每个厂商的垃圾回收器可能会完全不同,但是我们介绍的是基于JDK1.7之后的Hotspot虚拟机(包括前面对Java虚拟机的介绍也是基于jdk1.7版本的).在Hotspot中,虚拟机的收集器主要有下: 可以看到垃圾收集器是按对象的分代来划分的,可以用线条连接的垃圾回收器表示两者可以配合使用.可以看到新生代垃圾收集器有Serial.ParNew.Par

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

堆里面存放着Java世界几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还存活,哪些已经死去.判断对象的生命周期是否结束有以下几种方法 引用计数法 具体操作是给对象添加一个引用计数器,每当有一个地方引用时,计数器的值就加1,:当引用失效时,计数器就减1:任何时刻计数器为0的对象就 是不可能再被使用的.客观的说引用计数器算法实现简单,判定效率也很高,在大部分情况下他都是一个不错的算法.但是引用计数器有缺陷 举个简单的例子,对象A和对象B都有字段instance,

【转】Java垃圾收集器

原文链接 http://www.cnblogs.com/gw811/archive/2012/10/19/2730258.html#top Java垃圾收集器 概述 说起垃圾收集(Garbage Collection,GC),大部分人都把这项技术当做Java语言的伴生产物.事实上,GC的历史远远比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言.当Lisp还在胚胎时期时,人们就在思考: GC需要完成的三件事情: 哪些内存需要回收? 什么时候回收? 如