=====文章目录=====
强引用、软引用、弱引用与虚引用
强引用
使用new
方法创造出来的对象,默认都是强引用。GC的时候,就算内存不够,抛出OutOfMemoryError
也不会回收对象,死了也不回收。详见StrongReferenceDemo。
public class StrongReferenceDemo {
public static void main(String[] args) {
Object o1=new Object();
Object o2=new Object();
o1=null;
System.gc();
System.out.println(o2);
}
}
软引用
需要用Object.Reference.SoftReference
来显示创建。如果内存够,GC的时候不回收。内存不够,则回收。常用于内存敏感的应用,比如高速缓存。详见SoftReferenceDemo。
JVM配置单,故意产生大对象并配置小的内存,让它内存不够用导致OOM,看软引用的回收情况
条件1.创建大对象
byte[] bytes = new byte[30 * 1024 * 1024];//一个30M的对象
条件2.配置小的内存的方法
在 IDEA菜单栏---Run---Edit Configurations ---VM options
填写以下参数
-Xms5m -Xmx5m -XX:+PrintGCDetails
最后,右键run运行。
配置图
代码
import java.lang.ref.SoftReference;
public class SoftReferenceDemo {
public static void main(String[] args) {
System.out.println("软引用内存充足的情况");
softRef_Memory_Enough();
System.out.println();
System.out.println("软引用内存不足的情况");
softRef_Memory_NotEnough();
}
/**
* 内存够用的时候就保留,不够用就回收!
*/
private static void softRef_Memory_Enough() {
Object o1 = new Object();
SoftReference<Object> softReference = new SoftReference<>(o1);
System.out.println(o1);
System.out.println(softReference.get());
System.out.println("===========");
o1 = null;
System.gc();
System.out.println(o1);
System.out.println(softReference.get());
}
/**
* JVM配置单,故意产生大对象并配置小的内存,让它内存不够用导致OOM,看软引用的回收情况
* IDEA菜单栏---Run---Edit Configurations ---VM options---填写以下参数
* -Xms5m -Xmx5m -XX:+PrintGCDetails
* 右键run
*/
private static void softRef_Memory_NotEnough() {
Object o1 = new Object();
SoftReference<Object> softReference = new SoftReference<>(o1);
System.out.println(o1);
System.out.println(softReference.get());
System.out.println("===========");
o1 = null;
//System.gc();
try {
byte[] bytes = new byte[30 * 1024 * 1024];//一个30M的对象
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(o1);
System.out.println(softReference.get());
}
}
}
输出
弱引用
需要用Object.Reference.WeakReference
来显示创建。无论内存够不够,GC的时候都回收,也可以用在高速缓存上。详见WeakReferenceDemo
代码
import java.lang.ref.WeakReference;
public class WeakReferenceDemo {
public static void main(String[] args) {
Object o1 = new Object();
WeakReference<Object> weakReference = new WeakReference<>(o1);
System.out.println(o1);
System.out.println(weakReference.get());
System.out.println("==========");
o1 = null;
System.gc();
System.out.println(o1);
System.out.println(weakReference.get());
}
}
WeakHashMap
传统的HashMap
就算key==null
了,也不会回收键值对。但是如果是WeakHashMap
,一旦内存不够用时,且key==null
时,会回收这个键值对。详见WeakHashMapDemo。
package jvm;
import java.util.HashMap;
import java.util.WeakHashMap;
public class WeakHashMapDemo {
public static void main(String[] args) {
myHashMap();
System.out.println("===============");
myWeakHashMap();
}
private static void myHashMap() {
HashMap<Integer, String> map = new HashMap<>();
Integer key = 1;
String value = "HashMap";
map.put(key, value);
System.out.println(map);
key = null;
System.out.println(map);
System.gc();
System.out.println(map + "\t" + map.size());
}
private static void myWeakHashMap() {
WeakHashMap<Integer, String> map = new WeakHashMap<>();
// Integer key = 2;
Integer key = new Integer(2);
String value = "WeakHashMap";
map.put(key, value);
System.out.println(map);
key = null;
System.out.println(map);
System.gc();
System.out.println(map + "\t" + map.size());
}
}
输出
{
1=HashMap}
{
1=HashMap}
{
1=HashMap} 1
===============
{
2=WeakHashMap}
{
2=WeakHashMap}
{
} 0
虚引用
软应用和弱引用可以通过get()
方法获得对象,但是虚引用不行。虚引形同虚设,在任何时候都可能被GC,不能单独使用,必须配合引用队列(ReferenceQueue)来使用。设置虚引用的唯一目的,就是在这个对象被回收时,收到一个通知以便进行后续操作,有点像Spring
的后置通知。详见PhantomReferenceDemo。
引用队列
弱引用、虚引用被回收后,会被放到引用队列里面,通过poll
方法可以得到。关于引用队列和弱、虚引用的配合使用,见ReferenceQueueDemo。
代码
package jvm;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
public class PhantomReferenceDemo {
public static void main(String[] args) throws InterruptedException {
Object o1 = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
PhantomReference phantomReference = new PhantomReference(o1, referenceQueue);
System.out.println(o1);
System.out.println(phantomReference.get());
System.out.println(referenceQueue.poll());
System.out.println("===========");
o1 = null;
System.gc();
Thread.sleep(500);
System.out.println(o1);
System.out.println(phantomReference.get());
System.out.println(referenceQueue.poll());
}
}
输出
java.lang.Object@1b6d3586
null
null
===========
null
null
java.lang.ref.PhantomReference@4554617c
软引用与弱引用的适用场景
假如有一个应用需要读取大量的本地图片
- 如果每次读取图片都从硬盘读取则会严重影响性能,
- 如果一次性全部加载到内存中又可能造成内存溢出。
这时使用软引用可以解决这个问题
设计思路是:用一个 HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,
JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题
Map<String, SoftReference<Bitmap>> image Cache= new Hash Map<String, SoftReference<Bitmap>>0)