From 2eb16aa6ca5415ae4e741c4d1056890e07fa27e5 Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Sat, 9 May 2015 19:53:53 -0700 Subject: [PATCH] Remove SoftReference from dfs.DeltaBaseCache The Java GC doesn't always clear these before running out of memory and failing allocations. In practice OpenJDK 7 is leaving these live, removing any advantage of the SoftReference to attempt to shed memory when the GC is unable to continue allocating. Instead follow the pattern of the DfsBlockCache and use hard refs to the object data. Require applications to configure the cache size more accurately given expected memory usage. Change-Id: I87586b3e71b1cba0308a6a278d42e971be4bccd3 --- .../internal/storage/dfs/DeltaBaseCache.java | 89 +++++++------------ 1 file changed, 33 insertions(+), 56 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCache.java index c7bdbff8a..64a63d7c7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DeltaBaseCache.java @@ -43,7 +43,6 @@ package org.eclipse.jgit.internal.storage.dfs; -import java.lang.ref.SoftReference; /** * Caches recently used objects for {@link DfsReader}. @@ -60,34 +59,28 @@ private static int hash(long position) { } private int maxByteCount; - - private final Slot[] table; - - private Slot lruHead; - - private Slot lruTail; - private int curByteCount; + private final Entry[] table; + + private Entry lruHead; + private Entry lruTail; + DeltaBaseCache(DfsReader reader) { this(reader.getOptions().getDeltaBaseCacheLimit()); } DeltaBaseCache(int maxBytes) { maxByteCount = maxBytes; - table = new Slot[1 << TABLE_BITS]; + table = new Entry[1 << TABLE_BITS]; } Entry get(DfsPackKey key, long position) { - Slot e = table[hash(position)]; + Entry e = table[hash(position)]; for (; e != null; e = e.tableNext) { if (e.offset == position && key.equals(e.pack)) { - Entry buf = e.data.get(); - if (buf != null) { - moveToHead(e); - return buf; - } - return null; + moveToHead(e); + return e; } } return null; @@ -101,8 +94,7 @@ void put(DfsPackKey key, long offset, int objectType, byte[] data) { releaseMemory(); int tableIdx = hash(offset); - Slot e = new Slot(key, offset, data.length); - e.data = new SoftReference(new Entry(data, objectType)); + Entry e = new Entry(key, offset, objectType, data); e.tableNext = table[tableIdx]; table[tableIdx] = e; lruPushHead(e); @@ -110,16 +102,16 @@ void put(DfsPackKey key, long offset, int objectType, byte[] data) { private void releaseMemory() { while (curByteCount > maxByteCount && lruTail != null) { - Slot e = lruTail; - curByteCount -= e.size; + Entry e = lruTail; + curByteCount -= e.data.length; lruRemove(e); removeFromTable(e); } } - private void removeFromTable(Slot e) { + private void removeFromTable(Entry e) { int tableIdx = hash(e.offset); - Slot p = table[tableIdx]; + Entry p = table[tableIdx]; if (p == e) { table[tableIdx] = e.tableNext; @@ -138,16 +130,16 @@ private void removeFromTable(Slot e) { e.pack, Long.valueOf(e.offset))); } - private void moveToHead(final Slot e) { + private void moveToHead(Entry e) { if (e != lruHead) { lruRemove(e); lruPushHead(e); } } - private void lruRemove(final Slot e) { - Slot p = e.lruPrev; - Slot n = e.lruNext; + private void lruRemove(Entry e) { + Entry p = e.lruPrev; + Entry n = e.lruNext; if (p != null) { p.lruNext = n; @@ -162,8 +154,8 @@ private void lruRemove(final Slot e) { } } - private void lruPushHead(final Slot e) { - Slot n = lruHead; + private void lruPushHead(Entry e) { + Entry n = lruHead; e.lruNext = n; if (n != null) n.lruPrev = e; @@ -180,8 +172,8 @@ int getMemoryUsed() { int getMemoryUsedByLruChainForTest() { int r = 0; - for (Slot e = lruHead; e != null; e = e.lruNext) { - r += e.size; + for (Entry e = lruHead; e != null; e = e.lruNext) { + r += e.data.length; } return r; } @@ -189,43 +181,28 @@ int getMemoryUsedByLruChainForTest() { int getMemoryUsedByTableForTest() { int r = 0; for (int i = 0; i < table.length; i++) { - for (Slot e = table[i]; e != null; e = e.tableNext) { - r += e.size; + for (Entry e = table[i]; e != null; e = e.tableNext) { + r += e.data.length; } } return r; } static class Entry { + final DfsPackKey pack; + final long offset; + final int type; final byte[] data; - final int type; + Entry tableNext; + Entry lruPrev; + Entry lruNext; - Entry(final byte[] aData, final int aType) { - data = aData; - type = aType; - } - } - - private static class Slot { - final DfsPackKey pack; - - final long offset; - - final int size; - - Slot tableNext; - - Slot lruPrev; - - Slot lruNext; - - SoftReference data; - - Slot(DfsPackKey key, long offset, int size) { + Entry(DfsPackKey key, long offset, int type, byte[] data) { this.pack = key; this.offset = offset; - this.size = size; + this.type = type; + this.data = data; } } }