垃圾回收

如何判断一个对象是可回收的?

Java虚拟机采用可达性分析算法来判断对象是否存活。算法基本思想:通过一系列称为“GC Roots”的对象作为起点,从这些节点开始向下搜索,搜索锁走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,证明此对象是不可用的,将会被判定为可回收对象。

可作为GC Roots的对象:

虚拟机栈(栈帧中的局部变量表)中引用的对象

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

方法区中常量引用的对象

本地方法栈中JNI(native方法)引用的对象

强引用、软引用、弱引用、虚引用

强引用(Strong Reference):类似Object obj = new Object)的引用,存在强引用的对象,永远不会被GC。

软引用(Soft Reference):还有用但是非必须的对象。只存在软引用的对象,只有在内存不足时才被GC。可用来实现缓存(还没有被回收,直接获取对象),JDK中java.lang.ref.SoftReference用来实现软引用。

弱引用(Weak Reference):具有弱引用的对象具有更短的生命周期。只具有弱引用的对象,在垃圾收集器时会立即被回收,不管内存是否充足。JDK中java.lang.ref.WeakReference用来实现弱引用。

虚引用(Phantom Reference):一个对象是否有虚引用的存在不会影响对象的生命周期,也无法通过虚引用来获取一个对象的实例。唯一的用处:能在对象被GC时收到系统通知。JDK中java.lang.ref.PhantomReference用来实现虚引用。

垃圾收集算法

标记-清除算法:先标记所有要回收的对象,标记完成后统一回收。不足之处:标记清除效率较低;标记清除后会产生大量不连续的内存碎片,在后续为较大对象分配内存时,无法找到足够的连续内存而不得不再触发一次GC。

复制算法:将堆内存分为新生代和老年代,新生代分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor空间。当回收时,将Eden和Survivor中还存活着的对象一次性复制到另一块Survivor空间上,最后清理掉Eden和使用过的Survivor空间。解决了内存碎片问题。不足之处:在对象存活率较高时要进行较多的复制操作,效率会变低,如果第二块Survivor没有足够空间存放,需要依赖于其他内存(老年代)。

标记-整理算法:先标记所有要回收的对象,然后让存活的对象向一端移动,最后清理端边界意外的内存。

分代收集算法:对新生代和老年代采用不同的垃圾收集算法。新生代中每次垃圾收集时都发现有大量对象死去,只有少量对象存活,采用复制算法。老年代中对象存活率高,且没有额外空间进行分配担保,采用标记-清除算法或标记-整理算法。

垃圾收集器

Serial收集器:是一个单线程收集器,在进行垃圾回收时,必须暂停其他所有的工作线程,直到收集结束。试用于单个CPU的环境,由于没有线程交互的开销,收集效率高。(适用于在Client模式下运行的虚拟机)

ParNew收集器:是Serial收集器的多线程版本。是运行在Server模式下的虚拟机首选的新生代收集器,原因是除了Serial收集器外,目前只有它能与CMS收集器配合工作。

Parallel Scavenge收集器:是一个新生代收集器,使用复制算法。主要用于控制垃圾收集的吞吐量,可以通过参数精确的控制吞吐量,分别是控制最大垃圾收集停顿时间和吞吐量大小。常被称为“吞吐量优先”收集器。

Serial Old收集器:是serial收集器的老年代版本,也是一个单线程收集器,使用标记-整理算法。此收集器同Serial收集器一样,主要用于给Client模式下的虚拟机使用,如果在Server模式下使用,主要有两大用途:一是在JDK1.5之前与Parallel Scavenge收集器搭配使用;二是作为CMS收集器的后备方案,在并发收集器发生Concurrent Mode Failure时使用。

Parallel Old收集器:是Parallel Scavenge收集器的老年代版本,使用多线程和标记-整理算法。在JDK1.6之后可以和Parallel Scavenge收集器组合使用。

CMS收集器:(Concurrent Mark Sweep)是一种以获取最短回收停顿时间为目标的收集器,是基于标记 -清除算法实现的。运作过程分为4个步骤:

初始标记:标记GC Roots能直接关联到的对象,速度很快。

并发标记:进行GC Roots Tracing。即从GC Toots向下搜索并标记没有引用链的对象。

重新标记:修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。此阶段停顿时间会比初始标记阶段稍长,但远比并发标记的时间短。

并发清除:清除对象的过程。

其中初始标记和重新标记仍要暂停所有线程。整个过程中耗时最长的并发标记和并发清除过程收集器 线程都可以和用户线程一起工作,从整体上来说CMS收集器的内存回收过程与用户线程是并发执行的。

CSM收集器的缺点:

1、CMS收集器对CPU资源非常敏感。CMS默认启动的垃圾收集器线程数是(CPU数量+3)/4,当CPU数量较少时,垃圾收集器会占用大量CPU资源,导致用户线程执行速度降低,应用程序吞吐量降低。

2、CMS收集器无法处理浮动垃圾(CMS在并发清除阶段用户线程仍在运行,可能会产生新的垃圾,只能等待下一次GC时处理)。CMS收集器需要预留足够的内存给用户线程使用,因此不能等到老年代几乎满了再进行收集。JDK1.6之后,CMS收集器启动阈值设置为92%,即老年代使用了92%之后就启动CMS收集器。当CMS运行期间预留的内存无法满足程序的需要时,会出现“Concurrent Mode Failure”失败,这时会启用后备方案:临时启动Serial Old收集器来进行老年代垃圾回收。

3、CMS是基于标记-清除算法实现的,收集结束会产生大量空间碎片,可能会出现老年代还有大量空间剩余,但是无法找到足够大连续空间来为新对象分配内存,而不得不再触发一次Full GC。CMS提供了一个整理碎片的参数,默认开启,用于在CMS需要在Full GC时开启内存碎片的合并整理过程,内存整理过程无法并发执行,导致用户线程停顿时间变长。

G1收集器

GC的过程,GC对程序有什么影响?当发现虚拟机频繁GC时应该怎么办?

GC进行时必须停顿所有Java执行线程(Stop the world)

时间: 2024-12-29 01:08:56

垃圾回收的相关文章

Java垃圾回收原理(2)

Java虚拟机采用一种自适应的垃圾回收技术.依据的思想:对任何"活"的对象,一定能最终追溯到其存活在堆栈或静态存储区之中的引用.这个引用链条可能会穿过数个对象层次.由此,如果从堆栈和静态存储区开始,遍历所有的引用,就能找到所有活的对象.对于发现的每个引用,必须追踪它所引用的对象,然后是此对象所包含的所有的引用,如此反复进行,直到"根源于堆栈和静态存储区的引用"所形成的网络全部被访问为止.至于如何处理找到存活的对象,取决于不同的Java虚拟机的实现.有一种名为停止-复

Java性能优化之JVM GC(垃圾回收机制)

Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.stop-the-world 意味着JVM因为需要执行GC而停止了应用程序的执行.当stop-the-world 发生时,除GC所需的线程外,所有的线程都进入等待状态,直到GC任务完成.GC优化很多时候就是减少stop-the-world 的发生. JVM GC回收哪个区域内的垃圾? 需要注意的是,JV

JavaGC专家(1)—深入浅出Java垃圾回收机制

在学习GC之前,你首先应该记住一个单词:"stop-the-world".Stop-the-world会在任何一种GC算法中发生.Stop-the-world意味着 JVM 因为要执行GC而停止了应用程序的执行.当Stop-the-world发生时,除了GC所需的线程以外,所有线程都处于等待状态,直到GC任务完成.GC优化很多时候就是指减少Stop-the-world发生的时间. 按代的垃圾回收机制 在Java程序中不能显式地分配和注销内存.有些人把相关的对象设置为null或者调用Sy

CMS垃圾回收机制

详解CMS垃圾回收机制 原创不易,未经允许,不得转载~~~ 什么是CMS? Concurrent Mark Sweep. 看名字就知道,CMS是一款并发.使用标记-清除算法的gc. CMS是针对老年代进行回收的GC. CMS有什么用? CMS以获取最小停顿时间为目的. 在一些对响应时间有很高要求的应用或网站中,用户程序不能有长时间的停顿,CMS 可以用于此场景. CMS如何执行?  总体来说CMS的执行过程可以分为以下几个阶段: 3.1 初始标记(STW) 3.2 并发标记 3.3 并发预清理

JVM那些事儿(二)——垃圾回收

这节小汪介绍一下jvm的垃圾回收机制,首先我们先提问: 1.为什么要有不同的垃圾算法 2.垃圾回收器要解决的终极目的是什么 3.小汪该如何选择自己的垃圾回收器 一.垃圾回收算法 众所周知,java堆内存的垃圾回收由java虚拟机管理,目前java有几种算法用来解决垃圾回收(以下只介绍最重要的两个算法) 1.1 复制算法 如图所示,复制算法可以说是最直观最简洁的算法了.按照复制算法的思路,内存要分为两块 Eden Survivor区域,Eden有一个,Survivor有两个. 首先,各种对象都在E

终结处理和垃圾回收(1)

之前一直不了解Java的垃圾回收原理,最近看了Java编程思想,有点想法,做做笔记. 首先,我们都了解初始化的重要性,但是常常会忘记同样也重要的清理工作.Java有垃圾回收器负责回收无用对象占用的内存资源.但是也有特殊情况:假定你的对象(并非使用new)获得一块"特殊"的内存区域,由于垃圾回收器只知道释放那些经由new分配的内存,所以它不知道如何释放该对象的这块特殊内存.为了应对这种情况,Java允许在类中定义一个名为finalize()方法. Java的finalize()不同于C+

Java 垃圾回收机制(早期版本)

Java 垃圾回收机制在我们普通理解来看,应该视为一种低优先级的后台进程来实现的,其实早期版本的Java虚拟机并非以这种方式实现的. 先从一种很简单的垃圾回收方式开始. 引用计数 引用计数是一种简单但是速度很慢的垃圾回收技术. 每个对象都含有要给引用计数器,当有引用连接至对象时,引用计数+1. 当引用离开作用域或者被置为null时,引用计数-1. 当发现某个对象的引用计数为0时,就释放其占用的空间.   这种方法开销在整个程序生命周期中持续发生,并且该方法有个缺陷,如果对象之间存在循环引用,可能

Python中的垃圾回收机制

当我们声明一个对象的时候,例如str="abcdef",当我们不再使用str这个对象的时候,这个对象就是一个脏对象,垃圾对象,但是它还在占着内存,毕竟我们的电脑内存有限,所以应该有一个机制来回收它以及类似的对象.现在的高级语言如java,c#等,都采用了垃圾收集机制,而不再是c,c++里用户自己管理维护内存的方式.自己管理内存极其自由,可以任意申请内存,但如同一把双刃剑,为大量内存泄露,悬空指针等bug埋下隐患. 对于一个字符串.列表.类甚至数值都是对象,且定位简单易用的语言,自然不会

JVM垃圾回收2(垃圾收集算法)

根据<深入理解java虚拟机>这本书总结 一.关于几个概念:(标记垃圾算法.垃圾收集算法.垃圾收集器) 前面说了如何寻找jvm垃圾,有两种方法:引用计数法/可达性算法.这篇准备讲,标记完垃圾之后,回收的算法,这里的算法只是垃圾回收的思想.后面会讲到多种垃圾收集器,这里的垃圾收集器就是运用了垃圾手机算法的思想,可以说是具体实现. 这里还是想多余的说一下这三个概念: 垃圾标记算法:标记垃圾的方法 垃圾收集算法:一种回收思想,供垃圾收集器使用.可能用在年轻代,也可能用在老年代(当然现在来说老年代和年

深入理解JAVA虚拟机之JVM性能篇---垃圾回收

一.基本垃圾回收算法 1. 按基本回收策略分 1) 引用计数(Reference Counting)  对象增加一个引用,即增加一个计数,删除一个引用则减少一个计数.垃圾回收时,只用收集计数为0的对象.此算法最致命的是无法处理循环引用的问题. 2)标记-清除(Mark-Sweep)  执行分两阶段.第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除. 缺点是此算法需要暂停整个应用,同时会产生内存碎片. 3)复制(Copying) 把内存空间划为两个相等的区域,每