引用计数器法(Reference Counting)

引用计数器的实现很简单,对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失效时,引用计数器减1。只要对象A的引用计数器的值为0,则对象A不可能再被使用。

存在的问题:

l 无法处理循环引用,当对象A持有对象B的引用并且对象B持久对象A的引用,此时对象A和对象B的引用计数器都不为0。但是在系统中,却不存在任何第3个对象引用个A或B,此时A与b应该被回收,由于对象之间的相互引用导致垃圾回收期无法识别,引起内存泄漏。

l 引用计数器要求在每次引用产生和消除的时候,引用计数器需要加1或者减1对系统性能有一定影响。

由于以上原因JAVA并未采用此算法作为垃圾回收的算法

标记清除法(Mark-Sweep)

标记清除法将垃圾回收分为两个阶段:标记阶段和清除阶段。在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象(通过根对象进行引用搜索,最终可以到达的对象)。因此未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。

存在的问题:

l 标记清除算法可能产生空间碎片,回收后空间不是连续的,在对象的对空间分配过程中,尤其是大对象的内存分配,不连续内存空间会造成性能损耗。

复制算法(Copying)

将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中存活的对象复制到未使用的内存快中,之后清除正在使用的内存块中的对象,交换两个内存的角色,完成垃圾回收。复制算法可以确保内存空间是没有碎片的,但是复制算法的代价却是将系统内存折半。

JAVA新生代垃圾回收

Java新生代的串行垃圾回收器中,使用了复制算法的思想。新生代分为eden、from、to三部分空间。其中from和to空间可以视为用于复制的两块大小相同、地位相等、且角色可互换的内存块。From和to空间也成为survivor空间(s1、s0),即幸存者空间,哟关于存放末被回收的对象。

在垃圾回收时,eden空间中的存活对象会被复制到未使用的survivor空间中(假设是to),正在使用的survivor空间(假设是from)中的年轻对象也会被复制到to空间中(大对象,或者老年对象会直接进入老年代,如果to空间占满,则对象也会直接进入老年代)。并且年龄加一。此时eden空间与from空间中的剩余对象则是垃圾对象,直接清空,to空间则存放此次回收后的存活对象。

标记压缩法(Mark-Compact)

复制算法的高效性是建立在存活对象少,垃圾对象多的前提下。但是老年代更常见的情况是大部分对象是存活对象,所以老年代采用了标记压缩算法。和标记清除算法一样,它也需要从根节点开始,对所有可达对象做一次标记。但之后它并不是简单的清除未标记对象,而是将所有的存活对象压缩在内存的一端,之后清理边界外所有的空间。标记压缩算法也可以成为标记清除压缩(MarkSweepCompact)

分代算法

将内存区间根据对象的特点分成几块,根据每块内存区间的特点,使用不同的回收算法,以提高回收的效率。JAVA虚拟机会将所有新建对象放入新生代内存区域(除超过PretenureSizeThreshold参数限制的大对象直接进入老年代),新生代的特点是新建对象很快会被回收,所以新生代采用复制算法较为合适。当一个对象经过几次垃圾回收后依然存活(每次年龄+1通过MaxTenuringThreshold参数可设置当年龄达到N时移入老年代),对象将会被放入老年代内存。在老年代中,几乎所有对象都是经过几次垃圾回收后依然存活的,因此,可以认为这些对象在一段时间内,甚至在应用程序的整个生命周期中,将是常驻内存的。根据分代思想,可以对老年代的回收使用与新生代不同的标记压缩算法。JVM为了支持新生代高频率的回收使用了一种叫做卡表(Card Table)的数据接口,卡表为一个比特集合,每一个比特位可以用来表示老年代某一区域是否有新生代的引用。这样新生代GC时只需要先扫描卡表,当卡表的标记为1时,才需要扫描相应区域的老年代对象。卡表中每一位表示老年代4k的空间。

分区算法

分区算法将整个堆划分成连续的不同小区间,每一个小区间都是独立使用独立回收。这种算法可以控制一次回收多少个小区域。

判断是否回收

可触及性可以包含以下3种状态

l 可触及:从根节点开始,可以到达这个对象。

l 可复活:对象的所有引用被释放,但对象有可能在finalize()方法中复活。

l 不可触及:对象的finalize()函数被调用,并且没有复活。Finalize只能被调用一次

以上三种状态中,只有对象不可触及才可以被回收。

对象的复活

package com.hl.gc;public class ReliveObj {public static ReliveObj obj;@Overrideprotected void finalize() throws Throwable {super.finalize();obj = this;}@Overridepublic String toString() {return "relive";}public static void main(String[] args) throws InterruptedException {obj = new ReliveObj();obj = null;System.gc();Thread.sleep(10000);String str;str = obj!=null?"可用":"不可用";System.out.println("Relive obj"+str);System.out.println("第二次 gc");obj = null;System.gc();Thread.sleep(10000);str = obj!=null?"可用":"不可用";System.out.println("Relive obj"+str);}
}

不推荐使用finalize方法释放资源,因为finalize方法可能发生引用外泄,在无意中无货对象,而且finalize是被系统调用的,调用时间是不明确的,因此不是一个好的释放资源方案,推荐使用try-catch-finallly进行释放资源。

引用和GC回收强度

Java 7之基础 - 强引用、弱引用、软引用、虚引用

l 强引用(StrongReference)

强引用是最普遍的引用,强引用可直接访问目标对象,强引用所指向的对象在任何时候都不会被系统回收,即使抛出OOM异常也不会回收强引用所指向的对象。强引用可能会造成内存溢出。

l 软引用(SoftReference

GC未必会回收软引用的对象,但是当内存不足时,软引用对象会被回收。所以软引用不会引起内存溢出(通常用来作为缓存使用)。

l 弱引用(WeakReference)

在GC回收时,只要发现弱引用,不管系统的堆使用情况如何,都会将对象回收。但是由于回收器的线程通常优先级较低,因此并不一定能很快地发现持有弱引用的对象。(通常也作为缓存使用)

l 虚引用(PhantomReference

一个持有虚引用的对象和没有引用几乎是一样的,随时可能被垃圾回收器回收。当试图通过虚引用的get()方法取得强引用时,总是会失败。并且,虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收过程。当GC准备回收一个对象时,如果发现它还有虚引用,就会在回收对象后,将这个虚引用加入引用队列,已通知应用程序对象的回收情况。

垃圾回收的停顿现象:Stop-The-World

为了让垃圾回收器可以正常且高效的执行,大部分情况下,会要求系统进入一个停顿状态。停顿的目的是终止所有应用线程的执行,只有这样,系统中才不会产生新的垃圾,同时停顿保证了系统状态在某一个瞬间的一致性,有益于GC更好的标记垃圾对象。因此,在垃圾回收时,都会产生应用程序的停顿(STW),停顿产生时,整个应用程序会被卡死,没有任何响应。

©版权声明:本文为【翰林小院】(huhanlin.com)原创文章,转载时请注明出处!

转载于:https://blog.51cto.com/13925848/2160713

了解java虚拟机mdash;垃圾回收算法(5)相关推荐

  1. java虚拟机多久触发垃圾回收_每日一问:讲讲 Java 虚拟机的垃圾回收

    昨天我们用比较精简的文字讲了 Java 虚拟机结构,没看过的可以直接从这里查看: 每日一问:你了解 Java 虚拟机结构么? 今天我们必须来看看 Java 虚拟机的垃圾回收算法是怎样的.不过在开始之前 ...

  2. 学习笔记【Java 虚拟机②】垃圾回收

    若文章内容或图片失效,请留言反馈.部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 总目录 学习笔记[Java 虚拟机①]内存结构 学习笔记[Java 虚拟机②]垃圾回收 学习笔记[Java ...

  3. Java虚拟机之垃圾回收详解一

    Java虚拟机之垃圾回收详解一 Java技术和JVM(Java虚拟机) 一.Java技术概述: Java是一门编程语言,是一种计算平台,是SUN公司于1995年首次发布.它是Java程序的技术基础,这 ...

  4. ReviewForJob——java虚拟机的垃圾回收策略(个人总结)

    理解jvm的垃圾回收策略,需要解决以下3个问题 问题1:哪些内存需要回收? 问题2:什么时候进行回收? 问题3:怎样来回收? [解决问题1]哪些内存需要回收? jvm的内存区域有5大块: 1)程序计数 ...

  5. java虚拟机、垃圾回收、多线程

    虚拟机,我们都知道Java程序运行在虚拟机上,虚拟机又和操作系统打交道,最终通过二进制指令操纵电子电路运行.完成数据的读取,存储,运算和输出. 虚拟机在加载.class文件的时候,会在内存开辟一块区域 ...

  6. 深入理解Java虚拟机——JVM垃圾回收机制和垃圾收集器详解

    一:概述 说起垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联系起来.在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,顾名思义,垃圾回收就是释 ...

  7. java中的垃圾回收算法

    java中有四种垃圾回收算法,分别是: 标记清除法.标记整理法.复制算法.分代收集算法 1.标记清除法: 第一步:利用可达性去遍历内存,把存活对象和垃圾对象进行标记; 第二步:在遍历一遍,将所有标记的 ...

  8. Java虚拟机之垃圾回收

    1. 判断对象可以被回收 1.1 引用计数法 给对象添加一个引用计数器,每当用一个地方引用它时,计数器加一:当引用失效时,计数器减一,计数器为0的对象就是不可能再被使用的. 存在的弊端:循环引用,如下 ...

  9. 浅析Java虚拟机的垃圾回收机制(GC)

    目录 一.垃圾回收机制(Garbage Collection) 二.对象回收的时机 引用计数法 可达性分析算法 三.垃圾回收算法 标记-清除算法 标记-复制算法 标记-整理算法 新生代.老年代.永久代 ...

最新文章

  1. 【干货书】图、网络与算法
  2. SQL学习之组合查询(UNION)
  3. 7.4.3 矩阵极分解和平方根分解
  4. ES6之主要知识点(二) 变量的解构赋值。默认值
  5. java 上传图片后没法立马显示出来_SpringMVC多个文件上传及上传后立即显示图片功能...
  6. Java-java.util.concurrent.locks.AbstractQueuedSynchronizer
  7. As Foxit Software disclosed in its prospectus
  8. Mobx入门之四:自定义reactions,when, autorun
  9. vue-cli3+cordova实现app混合开发
  10. 转载:Windows Mobile 开发资源(精)
  11. c gui和java gui_C/C++编程GUI库比较
  12. 设计模式---状态模式(C++实现)
  13. 【java】超市购物小程序
  14. TTL转USB电路(CH340G)
  15. redis 学习笔记(六) sorted_set数据类型
  16. 极域电子书包课堂管理系统怎么控屏_极域电子教室使用说明
  17. G312高速公路S标段路线设计--金陵科技学院道路毕业设计
  18. 学习笔记 | 演化简单的程序用于玩 Atari 游戏
  19. ipad端网页屏幕变小了
  20. Springboot网站第三方登录——QQ登录

热门文章

  1. python配置文件密码管理_用户配置文件和密码配置文件,用户组管理和用户管理...
  2. 用Docker快速搭建一个博客网站,很简单的嘛~
  3. 码云上传项目时出现空目录的解决办法
  4. python 抓取电脑界面_学会了Python,我的人生跟开挂一样
  5. java swf 上传文件_[Pulgin] 利用swfupload实现java文件批量上传
  6. debian dhcp服务启动不了_网刻批量装系统pxe启动教程全自动分区装系统
  7. 51单片机c语言程序控制,51单片机C语言编程基础及实例.pdf
  8. python tkinter linux,用于Python和Tkinter的Linux上的字体管理
  9. 2019蓝桥杯Java决赛题答案_2019-01-15 第八届蓝桥杯javaB组第二题
  10. mysql 创建带参数的存储过程_在MySQL中创建带有IN和OUT参数的存储过程的方法