思维导图:点击查看思维导图.
1. 判断一个对象可以被回收
1.1.引用计数法
一个对象如果没有任何与之关联的引用,即他们的引用计数都不为 0,则说明对象不太可能再被用到,那么这个对象就是可回收对象。如果被引用则引用计数+1。可能产生循环引用问题。
1.2.可达性分析
通过一系列的“GC roots”对象作为起点搜索。如果在“GC roots”和一个对象之间没有可达路径,则称该对象是不可达的。不可达对象不一定是可回收对象。不可达对象变为可回收对象至少要经过两次标记。两次标记后仍然是可回收对象,则将面临回收。
打印垃圾回收详细参数
-XX:+PrintGCDetail -verbose:gc
2.四种引用
2.1. 强引用
在 Java 中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。只有所有GC Roots对象都不通过[强引用]该对象,该对象才会被垃圾回收。因此强引用是造成 Java 内存泄漏的主要原因之一。
2.2. 软引用
软引用需要用 SoftReference 类来实现,当系统内存足够时它就不会被回收,当系统内存空间不足时它会被回收。可以配合引用队列来释放软引用自身。软引用通常用在对内存敏感的程序中(内存不够,不重要的资源使用软引用)。
list对SoftReference强引用,byte[]对list弱引用
打印结果:
前4个对象为null已被回收!!!配合软引用队列后为软引用队列自身也将被回收,打印一个有值的对象地址!!
public static final int int_4MB = 4 * 1024 * 1024;
// -Xms15m -Xmx15m -Xmn10m
public static void main(String[] args) {
List<SoftReference<byte[]>> list = new ArrayList<>();
// 引用队列
ReferenceQueue<byte[]> queue = new ReferenceQueue();
for (int i = 0; i < 5; i++) {
// 关联引用队列,当软引用所关联的byte[]被回收时,软引用会自己加到queue引用队列中
SoftReference<byte[]> softReference = new SoftReference<>(new byte[int_4MB],queue);
System.out.println(softReference.get()); // 打印了5个 [B@1540e19d ......
list.add(softReference);
}
// 打印五个,前四个为null
System.out.println("----------------------");
for (SoftReference<byte[]> reference : list) {
System.out.println(reference.get()); // 打印4个null,一个[B@6d6f6e28
}
// 将为null的移除
// remove() 和 poll()都是用来从队列头部删除一个元素
// queue为空时remove抛异常,poll返回null
Reference<? extends byte[]> poll = queue.poll();
while (poll != null) {
list.remove(poll);
poll = queue.poll();
}
// 添加了五个,发现只剩下一个了
System.out.println("----------------------");
for (SoftReference<byte[