栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

黑马程序员jvm笔记(三)--垃圾回收部分

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

黑马程序员jvm笔记(三)--垃圾回收部分

8.垃圾回收 8.1.如何判断对象可以垃圾回收?

有两种判断类是不是垃圾的办法 分别是 引用计数法和可达性分析。

引用计数法

引用计数法有个弊端,循环引用时,两个对象的计数都为1,导致两个对象都无法被释放

例如老师视频里举的例子:

A对象引用了B对象,同时B对象引用了A对象,导致了循环引用。

可达性分析(jvm使用)

JVM中的垃圾回收器通过可达性分析来探索所有存活的对象扫描堆中的对象,看能否沿着GC Roott对象为起点的引用链找到该对象,如果找不到,则表示可以回收

可达性分析测试方法:使用jmap工具

将这个快照文件放到eslipce的Memory Analysis里进行解析,得到

可以作为GC Root的对象

虚拟机栈(栈帧中的本地变量表)中引用的对象。方法区中类静态属性引用的对象方法区中常量引用的对象本地方法栈中JNI(即一般说的Native方法)引用的对象 8.2.五种引用

强引用

只有GC Root都不引用该对象时,才会回收强引用对象

如上图B、C对象都不引用A1对象时,A1对象才会被回收

软引用

当GC Root指向软引用对象时,在内存不足时,会回收软引用所引用的对象

如上图如果B对象不再引用A2对象且内存不足时,软引用所引用的A2对象就会被回收

弱引用

只有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用所引用的对象

如上图如果B对象不再引用A3对象,则A3对象会被回收

弱引用的使用和软引用类似,只是将 SoftReference 换为了 WeakReference

虚引用

当虚引用对象所引用的对象被回收以后,虚引用对象就会被放入引用队列中,调用虚引用的方法

虚引用的一个体现是释放直接内存所分配的内存,当引用的对象ByteBuffer被垃圾回收以后,虚引用对象Cleaner就会被放入引用队列中,然后调用Cleaner的clean方法来释放直接内存如上图,B对象不再引用ByteBuffer对象,ByteBuffer就会被回收。但是直接内存中的内存还未被回收。这时需要将虚引用对象Cleaner放入引用队列中,然后调用它的clean方法来释放直接内存

终结器引用

所有的类都继承自Object类,Object类有一个finalize方法。当某个对象不再被其他的对象所引用时,会先将终结器引用对象放入引用队列中,然后根据终结器引用对象找到它所引用的对象,然后调用该对象的finalize方法。调用以后,该对象就可以被垃圾回收了

如上图,B对象不再引用A4对象。这是终结器对象就会被放入引用队列中,引用队列会根据它,找到它所引用的对象。然后调用被引用对象的finalize方法。调用以后,该对象就可以被垃圾回收了终结器引用有可能造成终结器对象指向的对象迟迟不被回收,因为该对象只有finallize方法被调用,才会被回收,而调用fianlly对象的线程优先度很低,不建议使用。

附加:引用队列

软引用和弱引用可以配合引用队列

在弱引用和虚引用所引用的对象被回收以后,会将这些引用放入引用队列中,方便一起回收这些软/弱引用对象 虚引用和终结器引用必须配合引用队列

虚引用和终结器引用在使用时会关联一个引用队列

软引用和弱引用的用处

我们看一个例子:

结果:堆内存溢出

因为用的是强引用对象,此时5个4m的对象会将内存填满,导致内存溢出 gc无法将其回收。

此时我们要使用软引用对象或者弱引用对象,让GC清理时清理掉之前的软引用和弱引用指向的对象,防止内存溢出。

软引用处理

可以看到 前四个元素都被清除,就剩下最后一个元素。

相关代码:

public class Demo1 {
	public static void main(String[] args) {
		final int _4M = 4*1024*1024;
		//使用软引用对象 list和SoftReference是强引用,而SoftReference和byte数组则是软引用
		List> list = new ArrayList<>();
		SoftReference ref= new SoftReference<>(new byte[_4M]);
	}
}

弱引用处理

道理和软引用基本相似。

而上面的两种处理后,即使软引用对象的指向对象被删除,软引用对象本身的内存没被释放,我们需要引用队列来清除它。

相关代码:

public class Demo1 {
	public static void main(String[] args) {
		final int _4M = 4*1024*1024;
		//使用引用队列,用于移除引用为空的软引用对象
		ReferenceQueue queue = new ReferenceQueue<>();
		//使用软引用对象 list和SoftReference是强引用,而SoftReference和byte数组则是软引用
		List> list = new ArrayList<>();
		SoftReference ref= new SoftReference<>(new byte[_4M]);

		//遍历引用队列,如果有元素,则移除
		Reference poll = queue.poll();
		while(poll != null) {
			//引用队列不为空,则从集合中移除该元素
			list.remove(poll);
			//移动到引用队列中的下一个元素
			poll = queue.poll();
		}
	}
}
8.3.垃圾回收算法 标记-清除法

定义:标记清除算法顾名思义,是指在虚拟机执行垃圾回收的过程中,先采用标记算法确定可回收对象,然后垃圾收集器根据标识清除相应的内容,给堆内存腾出相应的空间

标记-整理法

复制法

复制算法过程

8.4分代回收

jvm将堆内存分为新生代和老年代 ,新生代的幸存区用的是复制算法,老年代用的是标记-整理算法

详细过程为:

8.5.GC分析 大对象处理策略

当遇到一个较大的对象时,就算新生代的伊甸园为空,也无法容纳该对象时,会将该对象直接晋升为老年代

线程内存溢出

某个线程的内存溢出了而抛异常(out of memory),不会让其他的线程结束运行

这是因为当一个线程抛出OOM异常后,它所占据的内存资源会全部被释放掉,从而不会影响其他线程的运行,进程依然正常

附录:垃圾回收相关参数
含义                                      参数
堆初始大小                 -Xms
堆最大大小                -Xmx 或 -XX:MaxHeapSize=size
新生代大小                -Xmn 或 (-XX:NewSize=size + -XX:MaxNewSize=size )
幸存区比例            (动态) -XX:InitialSurvivorRatio=ratio 和 -XX:+UseAdaptiveSizePolicy
幸存区比例                -XX:SurvivorRatio=ratio
晋升阈值                  -XX:MaxTenuringThreshold=threshold
晋升详情                  -XX:+PrintTenuringDistribution
GC详情                   -XX:+PrintGCDetails -verbose:gc
FullGC前MinorGC          -XX:+ScavengeBeforeFullGC
8.6.垃圾回收器

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/727996.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号