java垃圾回收
一、概述
1、垃圾回收(GC,Garbage Collection):1960年诞生于MIT的Lisp。当需要排查各种内存溢出、内存泄漏的时候,当垃圾收集称为系统达到更高并发质量的瓶颈时,我们需要对这些“自动化”技术实施必要的监控和调节。GC主要用于完成三件事情:
a、那些内存需要回收
b、什么时候回收
c、如何回收
2、什么时候回收对象
在堆里存放着java中几乎所有的对象实例。垃圾收集器在对堆进行回收前。第一件事情就是要确定这些对象那些还活着,那些已经死去
1)引用计数算法:给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就建减一。
缺点:难以解决对象之间相互引用的问题。
2)可达性分析算法:通过一系列的称为“Gc Roots”的对象为起始点,从这些节点开始向下搜索,搜索走过的路径被称为引用链(Reference Chain),当一个对象到GC Roots没用任何引用链相连时,证明次对象是不可以用的。但所以会被判定为可回收的对象
eg、5,6,7可回收
GC Roots:虚拟机栈中的引用对象。方法区中的静态属性引用的对象、方法区中静态属性引用的对象、本地方法栈中JNI引用的对象
3)垃圾回收中的引用
a、我们前边的两个算法中中所提到的判断方法,都与“引用”有关。在JDK1.2之后,将引用分为强引用、软引用、弱引用、虚引用。这4种引用的强度依次依次减弱
强引用:在程序代码中普遍存在的,类似“Object obj = new Object()”这类的引用,只要强引用还在,垃圾收集器永远不会回收掉被引用的对象。
软引用:用来描述一些有用但是非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会将这些对象列进回收范围之中进行第二次回收。。SoftReference类来实现引用。
弱引用:描述非必需对象,比软引用更弱,被弱引用关联的对象只能生存道下一次垃圾收集发生之前,当垃圾收集器工作室,无论当前内存是否足够,都会回收掉之被弱引用关联的对象。WeskReference
虚引用:是最弱的一种引用,一个对象是否有虚引用,完全不会对生命周期构成影响。也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是在这个对象呗垃圾收集器回收时,收到一个系统通知。PhanReference
4)垃圾回收缓行执行
即使对象不可达,也不一定要被回收。如果对象没有与GC Roots相互连接的引用链,那么他就会被第一次标记,且进行一次筛选。
二、垃圾收集算法
1、标记-清除算法
1)首先标记出所有需要回收的对象,在标记完成之后统一回收所有被标记的对象。
2)缺点:
a、效率问题:标记和清除两个过程的效率不算高
b、空间问题:标记清除之后会产生大量不连续的内存碎片
2、复制算法
1)为了解决效率问题,复制算发可以将内存按照容量的大小划分为大小相等的两块,每次只使用其中的一块。当这一块内存用完了,就将还存活着的对象复制到另外一块上,然后把已经使用过的内存空间一次性清理。
2)优点:实现简单,运行高效
3)缺点:代价高昂
3、标记-整理算法
1)复制算法在对象存活率较高的时候要进行较多的复制操作,效率将会变得更低。更关键的是,如果不想浪费50%的空间,就需要有额外的空间进行分配担保。以应对被使用的内存中的对象都100%存活的极端情况。所以老年代一般不能直接选用这种算法。
标记-整理算法中,标记的过程与“标记-清除”中的标记算法一样,但是后续步骤不是直接清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
4、分代收集算法
1)更具对象存活周期的不同将内存划分为几块,一般是吧java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。新生代适合复制,老年代适合“标记-清除”和“标记-整理”。
三、HotSpot的算法实现
上边我们介绍了对象存活判定算法和垃圾收集算法,而在HotSpot虚拟机中,要实现这些算法,必须对算法的执行效率有严格的考量,才能保证虚拟机的高效运行。
1)枚举根节点
从可达性分析中从GC Roots节点找引用链这个操作为例子,可作为GC Rootts主要的全局性的引用(例如常量或静态属性)与执行上下文中
2)安全点 3)安全区域
四、垃圾收集器
收集算法是内存回收的方法论,垃圾收集器就是内存回收的具体实现。JAVA虚拟机规范中对垃圾收集器应该如何实现没有具体的规定,因此不同的厂商、不同的版本有很大的区别。
1、图中展示了七种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明它们可以搭配使用,虚拟机所处的区域,则表明它是属于新生代收集器还是老年代收集器。
2、Serial收集器
Serial收集器是最基本的、发展历史最悠久的收集器,这个收集器是一个单线程收集器,它的“单线程”说明的是,他进行垃圾收集时,必须暂停其他所有工作线程,直到它收集结束
优点:他依然是虚拟机运行在Client模式下的默认新生代收集器,简单而高效(与其他收集器的单线程比),对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然有着获得最高的单线程收集效率。
2、ParNew收集器
ParNew收集器其实就是Serical收集器的多线程版本,除了使用多线程进行垃圾收集之外,其余的行为包括Serial收集器可用的所有控制参数、收集算法、STop the World、对象分配规则、回收策略都与Sercial收集器完全一样。
3.G1收集器
G1是一款面向服务端应用垃圾收集器。HotSpot开发团队赋予他的使命是(在比较长期的)未来可以替换掉JDK1.5中发布的CMS收集器。与其他GC收集器相比G1具备如下特点。
并行与并发:G1能充分的利用多CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短Stop-The-World停顿的时间,部分其他收集器原本需要停顿java线程执行的Gc动作,G1收集器任然可以通过并发的方式让java程序继续执行。
分代收集:与其他收集器一样,分代的概念在G1中依然得以保留,虽然G1及恶意不需要其他收集器配合就能独立管理整个GC堆,但它能够有采用不同的方式去处理行创建的对象和以及存活率一段时间、熬过多次GC的就对象以获取更好的手机效果。
空间整合:与CMS的“标记--清理”算法不同,G1从整体上来看是基于“标记--整理”算法实现的数据收集。
可预测的停顿:能让使用者明确制定在一个长度为M浩渺的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这就已经是实施java的垃圾收集器的特征量。
G1收集器时,java堆的内存布局就与其他的收集器有很大的区别,他将整个java堆划分为多个大小相等的独立区域。虽然还保留着新生代和老年代的概念,但是新生代和老年代不再是物理隔离,他们是一部扽Region的集合。
1)Region之间对象应用导致的堆扫描解决方式
在G1收集器中,Region之间的对象引用以及其他收集器的中的新生代与老年代之间的对象应用,虚拟就都是使用了Remembered Set来避免全堆扫面的。G1中每个Region都有一个与之对应的Remembered Set,虚拟机发现程序对Reference类型的数据进行写操作室,会产生一个Write Barrier暂时中断写操作,检查Reference应用的对象是否处于不同的Region之间,如果是,便通过CardTable吧相关引用信息记录到被应用对象所属的Region的Remembered Set中。
2)G1:收集器的运作
a:初始标记(Initia Marking)
b:并发标记(COncurrent Marking)
c:最终标记(Final Marking)
d:筛选回收
四、GC日志
1)最前面的“33.125”和“100.667”:GC发生的时间,从虚拟机启动以来经过的秒数
2)GC日志开头的“[GC”和"[Full GC"说明了这次GC是发生了Stop-The-World的
3)接下来的“[DefNew”、“[Tenured”、“[Perm”表示GC发生的区域,这里的区域名称与使用的GC收集器是相关的,如果是Serial收集器为“[DefNew”,如果是ParNew收集器,新生代名称就回变为“[ParNew”。
4)后边的括号内部的“3324K->152K(3712k)”含义是:GC前内存区域已使用容量->GC后内存区域已使用容量(该内存区域总容量)。
5)方括号之外的"3324K->152K(11904K)"含义是:GC前java堆已使用容量->GC后Java堆已使用容量(Java堆总容量)
6)再往后“0.0025925 secs”表示该内存区域GC所占的时间,有的会给出更详细的时间,
以上是 java垃圾回收 的全部内容, 来源链接: utcz.com/z/393842.html