从Java SE2开始,就提供了四种类型的引用:强引用、软引用、弱引用和虚引用。Java中提供这四种引用类型主要有两个目的:第一是可以让程序员通过代码的方式决定某些对象的生命周期;第二是有利于JVM进行垃圾回收。四种级别由高到底分StrongReference,SoftReference,WeakRefrence.
一.StrongReference
java中最普遍的引用,只要某个对象有强引用与之关联,CG就绝对不会回收这部分内存,即使是内存不够跑出outofmemory也不会回收这份对象。
2
3
4
5
6
7
8
9
10
|
public
class
Main {
public
static
void
main(String[] args) {
new
Main().fun1();
}
public
void
fun1() {
Object object =
new
Object();
Object[] objArr =
new
Object[
1000
];
}
}
|
当运行至Object[] objArr = new Object[1000];这句时,如果内存不足,JVM会抛出OOM错误也不会回收object指向的对象。不过要注意的是,当fun1运行完之后,object和objArr都已经不存在了,所以它们指向的对象都会被JVM回收。
如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。
比如Vector类的clear方法中就是通过将引用赋值为null来实现清理工作的:
2
3
4
5
6
7
8
9
10
|
public
class
Main {
public
static
void
main(String[] args) {
new
Main().fun1();
}
public
void
fun1() {
Object object =
new
Object();
Object[] objArr =
new
Object[
1000
];
}
}
|
当运行至Object[] objArr = new Object[1000];这句时,如果内存不足,JVM会抛出OOM错误也不会回收object指向的对象。不过要注意的是,当fun1运行完之后,object和objArr都已经不存在了,所以它们指向的对象都会被JVM回收。
如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。
比如Vector类的clear方法中就是通过将引用赋值为null来实现清理工作的:
/** * Removes the element at the specified position in this Vector. * Shifts any subsequent elements to the left (subtracts one from their * indices). Returns the element that was removed from the Vector. * * @throws ArrayIndexOutOfBoundsException if the index is out of range * ({@code index < 0 || index >= size()}) * @param index the index of the element to be removed * @return element that was removed * @since 1.2 */ public synchronized E remove(int index) { modCount++; if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index); Object oldValue = elementData[index]; int numMoved = elementCount - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--elementCount] = null; // Let gc do its work return (E)oldValue; }
二.软引用(SoftReference)和弱引用(WeakReference)
如果一个对象只具有软引用,那么如果内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。(内存不够再释放)
如果一个对象只具有弱引用,那么在垃圾回收器线程扫描的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。弱引用也可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。(不论内存够不都会释放,不过CG是个优先级低的线程,可能不会马上把WeakReference回收掉)
我们还是以代码为例来说明,在Android中把图片缓存起来。
private Map<String,
2
3
4
5
6
7
8
9
10
|
public
class
Main {
public
static
void
main(String[] args) {
new
Main().fun1();
}
public
void
fun1() {
Object object =
new
Object();
Object[] objArr =
new
Object[
1000
];
}
}
|
当运行至Object[] objArr = new Object[1000];这句时,如果内存不足,JVM会抛出OOM错误也不会回收object指向的对象。不过要注意的是,当fun1运行完之后,object和objArr都已经不存在了,所以它们指向的对象都会被JVM回收。
如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。
比如Vector类的clear方法中就是通过将引用赋值为null来实现清理工作的:
private Map<String, SoftReference<Bitmap>> imgCache=new HashMap<String, SoftReference<Bitmap>>()public void addImgCache(String path){
// 强引用的Bitmap对象
Bitmap bitmap = BitmapFactory.decodeFile(path);
// 软引用的Bitmap对象
SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);
// 添加该对象到Map中使其缓存
imageCache.put(path, softBitmap);
}
获取的时候,可以通过SoftReference的get()方法得到Bitmap对象。
public BitMap getImgCache()String path){
SoftReference<Bitmap> softmap=imageCache.get(path);
// 判断是否存在软引用
if (softBitmap == null) {
return null;
}
// 取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空
Bitmap bitmap = softBitmap.get();
return bitmap;
}
经验分享:
到底什么时候使用软引用,什么时候使用弱引用呢?
个人认为,如果只是想避免OutOfMemory异常的发生,则可以使用软引用。如果对于应用的性能更在意,想尽快回收一些占用内存比较大的对象,则可以使用弱引用。
还有就是可以根据对象是否经常使用来判断。如果该对象可能会经常使用的,就尽量用软引用。如果该对象不被使用的可能性更大些,就可以用弱引用。另外,和弱引用功能类似的是WeakHashMap。WeakHashMap对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的回收,回收以后,其条目从映射中有效地移除。WeakHashMap使用ReferenceQueue实现的这种机制。