问题描述:
-
项目中存在大量使用 Hashmap 的情况,存在如下问题
- HashMap 内部创建的数组和其他对象无法复用,带来内存回收的压力
- 代码规范问题,有的RD会在构造方法中带
capacity有的不会,这样导致问题复杂度提升
-
ArrayMap 实现了数组的缓存,针对移动端开发场景更适合
- 需要明确不带
capacity时的实现机制
- 需要明确不带
问题跟踪:
1、不带 capacity 的构造参数
/**
* Create a new empty ArrayMap. The default capacity of an array map is 0, and
* will grow once items are added to it.
*/
public ArrayMap() {
this(0, false);
}
public ArrayMap(int capacity, boolean identityHashCode) {
mIdentityHashCode = identityHashCode;
// If this is immutable, use the sentinal EMPTY_IMMUTABLE_IN
// instance instead of the usual EmptyArray.INT. The referen
// is checked later to see if the array is allowed to grow.
if (capacity < 0) {
mHashes = EMPTY_IMMUTABLE_INTS;
mArray = EmptyArray.OBJECT;
} else if (capacity == 0) {
mHashes = EmptyArray.INT;
mArray = EmptyArray.OBJECT;
} else {
allocArrays(capacity);
}
mSize = 0;
}
capacity 为 0 时 mHashes 和 mArray 两个数组对应的初始值为 EmptyArray 中的空数组
public final class EmptyArray {
...
public static final int[] INT = new int[0];
public static final Object[] OBJECT = new Object[0];
...
}
2、map.put(key, value) 实现
public V put(K key, V value) {
final int osize = mSize;
final int hash;
int index;
if (key == null) {
hash = 0;
index = indexOfNull();
} else {
hash = mIdentityHashCode ? System.identityHashCode(key) : key.hashCode();
// 这里因为 mSize 为 0 ,所以返回的值为 ~0 = -1
index = indexOf(key, hash);
}
if (index >= 0) {
index = (index<<1) + 1;
final V old = (V)mArray[index];
mArray[index] = value;
return old;
}
index = ~index;
if (osize >= mHashes.length) {
// 扩容策略
final int n = osize >= (BASE_SIZE*2) ? (osize+(osize>>1))
: (osize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE);
if (DEBUG) Log.d(TAG, "put: grow from " + mHashes.length + " to " + n);
final int[] ohashes = mHashes;
final Object[] oarray = mArray;
allocArrays(n);
if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
throw new ConcurrentModificationException();
}
if (mHashes.length > 0) {
if (DEBUG) Log.d(TAG, "put: copy 0-" + osize + " to 0");
System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
System.arraycopy(oarray, 0, mArray, 0, oarray.length);
}
freeArrays(ohashes, oarray, osize);
}
if (index < osize) {
if (DEBUG) Log.d(TAG, "put: move " + index + "-" + (osize-index)
+ " to " + (index+1));
System.arraycopy(mHashes, index, mHashes, index + 1, osize - index);
System.arraycopy(mArray, index << 1, mArray, (index + 1) << 1, (mSize - index) << 1);
}
if (CONCURRENT_MODIFICATION_EXCEPTIONS) {
if (osize != mSize || index >= mHashes.length) {
throw new ConcurrentModificationException();
}
}
mHashes[index] = hash;
mArray[index<<1] = key;
mArray[(index<<1)+1] = value;
mSize++;
return null;
}
这里不再贴出缓存相关的代码
问题结论:
- ArrayMap 实现了数组对象的复用,能减少垃圾回收的压力
- ArrayMap 设计时考虑了并发的安全性问题,是因为设计时就考虑了更广泛的场景