Reference
C++中有指针和Reference的概念,指针可以重新赋值,而Reference只能初始化时赋值。
然而,java中的Reference是可以重新赋值,并不是C++的Reference概念,类似于C++的指针的概念。
WeakReference和Strong Reference
通常实例化的操作就是强引用:
Object obj = new Object();
obj强引用new Object()在堆上分配的空间。
只有执行obj=null; 时,new Object()在堆上分配的内存才会失去引用,可以被GC回收。
弱引用声明:
WeakReference
这样ref_obj弱引用new Object()在堆上分配的空间。
当GC被触发时,就会回收或者稍后回收heap空间。
HashMap(put方法)添加对象引用
@Override public V put(K key, V value) {
if (key == null) {
return putValueForNullKey(value);
}
int hash = Collections.secondaryHash(key);
HashMapEntry[] tab = table;//---------------------HashMap数据存于HashMapEntry数组内。
int index = hash & (tab.length - 1);
for (HashMapEntry e = tab[index]; e != null; e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
preModify(e);
V oldValue = e.value;
e.value = value;//-----------------------Heap Object赋值给HashMapEntry的value变量。
return oldValue;
}
}
// No entry for (non-null) key is present; create one
modCount++;
if (size++ > threshold) {
tab = doubleCapacity();
index = hash & (tab.length - 1);
}
addNewEntry(key, value, hash, index);
return null;
}
static class HashMapEntry implements Entry { //----------实现Entry接口,并没有WeakReference。
final K key;
V value;
final int hash;
HashMapEntry next;
.... ...
而WeakHashMap的put方法:
@Override
public V put(K key, V value) {
poll();
int index = 0;
Entry entry;
if (key != null) {
index = (Collections.secondaryHash(key) & 0x7FFFFFFF) % elementData.length;
entry = elementData[index];//-----------------------------------------------WeakHashMap的数据依然存于数组:Entry[] elementData;
while (entry != null && !key.equals(entry.get())) {
entry = entry.next;
}
} else {
entry = elementData[0];
while (entry != null && !entry.isNull) {
entry = entry.next;
}
}
if (entry == null) {
modCount++;
if (++elementCount > threshold) {
rehash();
index = key == null ? 0 : (Collections.secondaryHash(key) & 0x7FFFFFFF)
% elementData.length;
}
entry = new Entry(key, value, referenceQueue);//-------------------Heap Object(key和value)赋给了Entry对象的key和value属性。
entry.next = elementData[index];
elementData[index] = entry;
return null;
}
V result = entry.value;
entry.value = value;
return result;
}
private static final class Entry extends WeakReference implements //-----------WeakHashMap中的Entry是继承WeakReference.
Map.Entry {
final int hash;
boolean isNull;
V value;
Entry next;
... ...
ArrayList(add方法)添加对象的引用
@Override public boolean add(E object) {
Object[] a = array;
int s = size;
if (s == a.length) {
Object[] newArray = new Object[s +
(s < (MIN_CAPACITY_INCREMENT / 2) ?
MIN_CAPACITY_INCREMENT : s >> 1)];//---------------ArrayList也是将数据存于数组。【LinkedList并不是存于数组】
System.arraycopy(a, 0, newArray, 0, s);//-------------------这个方法对数组扩容,并保证添加顺序不变。
array = a = newArray;
}
a[s] = object;//------------------------------Heap Object赋给了数组的最后一个位置。
size = s + 1;
modCount++;
return true;
}
@Override public void clear() {
if (size != 0) {
Arrays.fill(array, 0, size, null);//----------将null赋给array中从0到size位置的所有元素。
size = 0;
modCount++;
}
}
public static void fill(Object[] array, int start, int end, Object value) {
Arrays.checkStartAndEnd(array.length, start, end);
for (int i = start; i < end; i++) {
array[i] = value;//------------------------------将start到end位置的array元素都赋值为null.
}
}
显然,ArrayList是对object的强引用。而clear()方法,是将所有引用置空,这样就是可以使E object在GC触发时得到回收。
而List并没有现成的WeakList。
LRU策略
LRU(Least Recently Used)是利用“强引用”LinkedHashMap(将accessOrder设为true)存储数据。
通过LinkedHashMap的eldest()方法获取到最老(使用次数最低)的Entry eldest,
然后通过LruCache类的put(K,V)方法将数据添加到LinkedHashMap map中,当map中所有V的大小总和大于LruCache所设置的最大值maxSize时,就调用map.remove(K)方法,使V(Heap Object)失去Entry的引用,以达到便于GC回收这部分内存的目的。
/**
* True if access ordered, false if insertion ordered.
*/
private final boolean accessOrder;//-------true,则按照访问的顺序排序。
public LinkedHashMap() {
init();
accessOrder = false;//------------------默认是false,按照插入的顺序排序。
}
public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}
V previous;
synchronized (this) {
putCount++;
size += safeSizeOf(key, value);
previous = map.put(key, value);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, value);
}
trimToSize(maxSize);//------------每次添加数据,都要判断缓存大小。
return previous;
}
public void trimToSize(int maxSize) {
while (true) {
K key;
V value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName()
+ ".sizeOf() is reporting inconsistent results!");
}
if (size <= maxSize) {
break;
}
Map.Entry toEvict = map.eldest();
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);//---------------------当size>maxSize了,则map.remove();
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
@Override public V remove(Object key) {
if (key == null) {
return removeNullKey();
}
int hash = Collections.secondaryHash(key);
HashMapEntry[] tab = table;
int index = hash & (tab.length - 1);
for (HashMapEntry e = tab[index], prev = null;
e != null; prev = e, e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
if (prev == null) {
tab[index] = e.next;
} else {
prev.next = e.next;
}
modCount++;
size--;
postRemove(e);//-----------------------------HashMap的remove后,调用了空实现方法postRemove();
return e.value;
}
}
return null;
}
@Override void postRemove(HashMapEntry e) {//----------------LinkedHashMap方法覆写了postRemove方法,
LinkedEntry le = (LinkedEntry) e;
le.prv.nxt = le.nxt;
le.nxt.prv = le.prv;
le.nxt = le.prv = null; // Help the GC (for performance)//-------------将Heap Object失去LinkedEntry le的引用,以便GC回收。
}
Lru策略,最终只是将Heap Object失去引用,并未强制触发GC,所以LruCache的maxSize的设定不应该接近android虚拟机的最大Heap Size,否则同样容易引起内存溢出!!!