06.26 JVM内存-GC策略

JVM内存-GC策略

在思考GC时通常需要完成3件事情:

哪些内存需要回收?什么时候回收?如何回收?

引用计数器算法GC存在的问题是?

描述:引用计数器法给对象中添加一个引用计数器,没当一个地方引用它,计数器就加一,引用失效时减一,任何引用计数器为0的对象就是不可能再被使用的对象。

引用计数器算法的效率也比较高,主流的JVM里面并没有选用引用计数器来管理内存,其中最主要的问题是不能解决对象之间循环引用的问题。

jvm可达性分析算法

java是通过可达性分析来判断对象是否存活,这个算法的基本思路是通过一系列的称为“GC Roots”的对象为起始点,从这些节点向下搜索,搜索所有的路径称为引用链;引用链不能到达的对象节点是GC需要回收的。

在java语言中可被称为“GC Roots”的对象包括下面几个方面:

1.虚拟机栈中引用的对象2.方法区中类静态属性引用的对象3.方法区中常量引用的对象4.本地方法(Native)引用的对象

无论是引用计数器还是可达性分析判断的标准都是对象是否引用。

在jdk1.2后,java对引用进行了扩充,将引用分为强引用 、软引用、弱引用、虚引用4种,强弱依次递减。

强引用:类似“Object obj = new Object()”,只要存在,GC永不回收

public class Main {
public static void main(String[] args) {
new Main().fun1();
}

public void fun1() {
Object object = new Object();
Object[] objArr = new Object[1000];
}
}
软引用:软引用是用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。如:

import java.lang.ref.SoftReference;

public class Main {
public static void main(String[] args) {

SoftReference<string> sr = new SoftReference<string>(new String("hello"));
System.out.println(sr.get());
}
}
/<string>/<string>弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。下面是使用示例:

public class Main {
public static void main(String[] args) {



WeakReference<string> sr = new WeakReference<string>(new String("hello"));

System.out.println(sr.get());
System.gc(); //通知JVM的gc进行垃圾回收
System.out.println(sr.get());
}
}
/<string>/<string>虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。

ReferenceQueue<string> queue = new ReferenceQueue<string>();
PhantomReference<string> pr = new PhantomReference<string>(new String("hello"), queue);
System.out.println(pr.get());
/<string>/<string>/<string>/<string>

如何利用软引用和弱引用解决OOM问题

前面讲了关于软引用和弱引用相关的基础知识,那么到底如何利用它们来优化程序性能,从而避免OOM的问题呢?

下面举个例子,假如有一个应用需要读取大量的本地图片,如果每次读取图片都从硬盘读取,则会严重影响性能,但是如果全部加载到内存当中,又有可能造成内存溢出,此时使用软引用可以解决这个问题。

设计思路是:用一个HashMap来保存图片的路径 和 相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。在Android开发中对于大量图片下载会经常用到。

生存还是死亡

要宣告一个对象死亡,至少经历两次标记过程:如果进行可达性分析时没有到达的引用链,将会做第一次标记,此处需要进行一次筛选,条件是有必要执行finalize()方法,当对象没有覆盖finalize(),或者已经被jvm调用,这两种情况称为“没有必要执行”;如果对象被判断有必要执行,会被放置在一个F-Queue队列,稍后有优先级低的线程进行第二次标记,如果对象finalize重新进行了引用,那么将会移出回收队列,否则会被进行垃圾回收。

回收方法区

判断一个类需要回收的条件:

该类的所有实例已经被回收,也就是堆中不存在该类的实例加载该类的ClassLoader已经被回收该类的Class对象没有在任何地方引用,没有使用到反射的方法

如果对java微服务、分布式、高并发、高可用、大型互联网架构技术、面试经验交流。感兴趣可以关注我的头条号,我会在微头条不定期的发放免费的资料链接,这些资料都是从各个技术网站搜集、整理出来的,如果你有好的学习资料可以私聊发我,我会注明出处之后分享给大家。欢迎分享,欢迎评论,欢迎转发。