了解java虚拟机—垃圾回收算法(5)
引用计数器法(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;
@Override
protected void finalize() throws Throwable {
super.finalize();
obj = this;
}
@Override
public 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回收强度
l 强引用(StrongReference)
强引用是最普遍的引用,强引用可直接访问目标对象,强引用所指向的对象在任何时候都不会被系统回收,即使抛出OOM异常也不会回收强引用所指向的对象。强引用可能会造成内存溢出。
l 软引用(SoftReference)
GC未必会回收软引用的对象,但是当内存不足时,软引用对象会被回收。所以软引用不会引起内存溢出(通常用来作为缓存使用)。
l 弱引用(WeakReference)
在GC回收时,只要发现弱引用,不管系统的堆使用情况如何,都会将对象回收。但是由于回收器的线程通常优先级较低,因此并不一定能很快地发现持有弱引用的对象。(通常也作为缓存使用)
l 虚引用(PhantomReference)
一个持有虚引用的对象和没有引用几乎是一样的,随时可能被垃圾回收器回收。当试图通过虚引用的get()方法取得强引用时,总是会失败。并且,虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收过程。当GC准备回收一个对象时,如果发现它还有虚引用,就会在回收对象后,将这个虚引用加入引用队列,已通知应用程序对象的回收情况。
垃圾回收的停顿现象:Stop-The-World
为了让垃圾回收器可以正常且高效的执行,大部分情况下,会要求系统进入一个停顿状态。停顿的目的是终止所有应用线程的执行,只有这样,系统中才不会产生新的垃圾,同时停顿保证了系统状态在某一个瞬间的一致性,有益于GC更好的标记垃圾对象。因此,在垃圾回收时,都会产生应用程序的停顿(STW),停顿产生时,整个应用程序会被卡死,没有任何响应。
©版权声明:本文为【翰林小院】(huhanlin.com)原创文章,转载时请注明出处!
了解java虚拟机—垃圾回收算法(5)的更多相关文章
- JAVA虚拟机垃圾回收算法原理
除了释放不再被引用的对象外,垃圾收集器还要处理堆碎块.新的对象分配了空间,不再被引用的对象被释放,所以堆内存的空闲位置介于活动的对象之间.请求分配新对象时可能不得不增大堆空间的大小,虽然可以使用的总空 ...
- java虚拟机-垃圾回收算法
在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理.但是首先需要明确,什么样的对象才能当为垃圾: 1.引用计数法:如果某个引用(即指针)指向对象,那么说明该对象还 ...
- Java虚拟机—垃圾回收算法(整理版)
1.概述 由于垃圾收集算法的实现涉及大量的程序细节.因此本节不打算过多地讨论算法的实现,只是介绍几种算法的思想及其发展过程.主要涉及的算法有标记-清除算法.复制算法.标记-整理算法.分代收集算法. 2 ...
- Java虚拟机垃圾回收(二) :垃圾回收算法(转载)
1.标记-清除算法 标记-清除(Mark-Sweep)算法是一种基础的收集算法. 1.算法思路 "标记-清除"算法,分为两个阶段: (A).标记 首先标记出所有需要回收的对象: 标 ...
- Java虚拟机垃圾回收(三) 7种垃圾收集器
Java虚拟机垃圾回收(三) 7种垃圾收集器 主要特点 应用场景 设置参数 基本运行原理 在<Java虚拟机垃圾回收(一) 基础>中了解到如何判断对象是存活还是已经死亡?在<Java ...
- Java虚拟机垃圾回收:内存分配与回收策略 方法区垃圾回收 以及 JVM垃圾回收的调优方法
在<Java对象在Java虚拟机中的创建过程>了解到对象创建的内存分配,在<Java内存区域 JVM运行时数据区>中了解到各数据区有些什么特点.以及相关参数的调整,在<J ...
- Java虚拟机垃圾回收(三): 7种垃圾收集器(转载)
1.垃圾收集器概述 垃圾收集器是垃圾回收算法(标记-清除算法.复制算法.标记-整理算法.火车算法)的具体实现,不同商家.不同版本的JVM所提供的垃圾收集器可能会有很在差别,本文主要介绍HotSpot虚 ...
- Java虚拟机垃圾回收:基础点(转载)
1.Java虚拟机垃圾回收 垃圾回收,或称垃圾收集(Garbage Collection,GC)是指自动管理回收不再被引用的内存数据. 在1960年诞生于MIT的Lisp语言首次使用了动态内存分配和垃 ...
- ☕【JVM技术指南】「JVM总结笔记」Java虚拟机垃圾回收认知和调优的"思南(司南)"【下部】
承接上文 (完结撒花1-52系列)[JVM技术指南]「JVM总结笔记」Java虚拟机垃圾回收认知和调优的"思南(司南)"[上部] 并行收集器 并行收集器(也称为吞吐量收集器)是类似 ...
随机推荐
- WPF 右上角带数字的按钮
效果如图所示 三种方案, 1:不改控件模版,布局实现,死开 2:改button模版,利用附加属性,附加附加属性,功能多了话,不利于拓展 3:继承button,添加依赖属性,接下来是这种 1:新建类 为 ...
- .net程序和管理员权限的一些事
1.对某个方法设置管理员权限运行(未考证)(假的,必须以管理员权限启动,不然报错) [PrincipalPermission(SecurityAction.Demand, Role = @" ...
- 【洛谷4238】 多项式求逆(NTT,分治)
前言 多项式求逆还是爽的一批 Solution 考虑分治求解这个问题. 直接每一次NTT一下就好了. 代码实现 #include<stdio.h> #include<stdlib.h ...
- [转]高端又易学的vbs表白程序了解一下
第一个. 打开txt文件,复制以下代码粘贴进去(可以修改中文部分,其它代码不要动!).保存并关闭txt文件. msgbox("做我女朋友好吗?") msgbox("房产证 ...
- js中获取当前页面的url
在js中可以通过下面的方式获取当前页面url的相关信息 var item = window.location // 返回的是对象, 这个对象里有各种关于url的信息 var url = window. ...
- flask的变量和函数
flask 中有内置的的变量函数 ,那些特殊的变量可以实现某些功能 config :可以从模板中直接访问Flask当前的config对象:{{config.SQLALCHEMY_DATABASE_UR ...
- 12-01 Java Scanner类,Scanner类中的nextLine()产生的换行符问题
分析理解:Scanner sc = new Scanner(System.in); package cn.itcast_01; /* * Scanner:用于接收键盘录入数据. * * 前面的时候: ...
- How To Scan QRCode For UWP (4)
QR Code的全称是Quick Response Code,中文翻译为快速响应矩阵图码,有关它的简介可以查看维基百科. 我准备使用ZXing.Net来实现扫描二维码的功能,ZXing.Net在Cod ...
- Java模式—简单工厂模式
简单工厂模式:是由一个工厂对象决定创建出哪一种产品类的实例,简单工厂模式是工厂模式家族中最简单实用的模式. 目的:为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. ...
- windows cmd窗口提示“telnet”命令不能内部或外部命令,也不是可运行的程序
windows cmd窗口提示“telnet”命令不能内部或外部命令,也不是可运行的程序 原因:C:\Windows\System32目录下没有telnet.exe,path系统变量的值包含了C:\W ...