diff options
author | Dinnerbone <dinnerbone@dinnerbone.com> | 2011-03-09 22:12:28 +0000 |
---|---|---|
committer | Dinnerbone <dinnerbone@dinnerbone.com> | 2011-03-09 22:12:28 +0000 |
commit | 0df1d1a1011d16562e4d5d1d6fd60182a0508401 (patch) | |
tree | fece752d5aba07b62545d63fabc644cee2177c6c /src | |
parent | 507e2be8ea837aa06c33d158ccc25270b62d832a (diff) | |
download | craftbukkit-0df1d1a1011d16562e4d5d1d6fd60182a0508401.tar craftbukkit-0df1d1a1011d16562e4d5d1d6fd60182a0508401.tar.gz craftbukkit-0df1d1a1011d16562e4d5d1d6fd60182a0508401.tar.lz craftbukkit-0df1d1a1011d16562e4d5d1d6fd60182a0508401.tar.xz craftbukkit-0df1d1a1011d16562e4d5d1d6fd60182a0508401.zip |
Changed block cache to soft references (should help a lot with memory usage)
Diffstat (limited to 'src')
-rw-r--r-- | src/main/java/org/bukkit/craftbukkit/CraftChunk.java | 3 | ||||
-rw-r--r-- | src/main/java/org/bukkit/craftbukkit/util/SoftMap.java | 200 |
2 files changed, 202 insertions, 1 deletions
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java index c9469f5d..24459f06 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -10,10 +10,11 @@ import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.util.SoftMap; public class CraftChunk implements Chunk { private WeakReference<net.minecraft.server.Chunk> weakChunk; - private final HashMap<Integer, Block> cache = new HashMap<Integer, Block>(); + private final SoftMap<Integer, Block> cache = new SoftMap<Integer, Block>(); private WorldServer worldServer; private int x; private int z; diff --git a/src/main/java/org/bukkit/craftbukkit/util/SoftMap.java b/src/main/java/org/bukkit/craftbukkit/util/SoftMap.java new file mode 100644 index 00000000..1b8f6c47 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/util/SoftMap.java @@ -0,0 +1,200 @@ +package org.bukkit.craftbukkit.util; + +import java.util.Map; +import java.util.AbstractMap; +import java.util.LinkedList; +import java.util.HashMap; +import java.util.Set; +import java.util.Collection; +import java.util.Iterator; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; + +/** + * Creates a map that uses soft reference. This indicates to the garbage collector + * that they can be removed if necessary + * + * A minimum number of strong references can be set. These most recent N objects added + * to the map will not be removed by the garbage collector. + * + * Objects will never be removed if they are referenced strongly from somewhere else + + * Note: While data corruption won't happen, the garbage collector is potentially async + * This could lead to the return values from containsKey() and similar methods being + * out of date by the time they are used. The class could return null when the object + * is retrieved by a .get() call directly after a .containsKey() call returned true + * + * @author raphfrk + */ + +public class SoftMap<K,V> { + + private final HashMap<K,SoftMapReference<K,V>> map = new HashMap<K,SoftMapReference<K,V>>(); + private final ReferenceQueue<SoftMapReference> queue = new ReferenceQueue<SoftMapReference>(); + private final LinkedList<V> strongReferenceQueue = new LinkedList<V>(); + private final int strongReferenceSize; + + public SoftMap() { + this(20); + } + + public SoftMap(int size) { + strongReferenceSize = size; + } + + // When a soft reference is deleted by the garbage collector, it is set to reference null + // and added to the queue + // + // However, these null references still exist in the HashMap as keys. This method removes these keys. + // + // It is called whenever there is a method call of the map. + + private void emptyQueue() { + SoftMapReference ref; + while((ref=(SoftMapReference)queue.poll()) != null) { + map.remove(ref.key); + } + } + + public void clear() { + strongReferenceQueue.clear(); + map.clear(); + emptyQueue(); + } + + // Shouldn't support this, since the garbage collection is async + + public boolean containsKey(K key) { + emptyQueue(); + return map.containsKey(key); + } + + // Shouldn't support this, since the garbage collection is async + + public boolean containsValue(V value) { + emptyQueue(); + return map.containsValue(value); + } + + // Shouldn't support this since it would create strong references to all the entries + + public Set entrySet() { + emptyQueue(); + throw new UnsupportedOperationException("SoftMap does not support this operation, since it creates potentially stong references"); + } + + // Doesn't support these either + + public boolean equals(Object o) { + emptyQueue(); + throw new UnsupportedOperationException("SoftMap doesn't support equals checks"); + } + + // This operation returns null if the entry is not in the map + + public V get(K key) { + emptyQueue(); + return fastGet(key); + } + + private V fastGet(K key) { + SoftMapReference<K,V> ref = map.get(key); + if(ref==null) { + return null; + } + V value = ref.get(); + if(value!=null) { + strongReferenceQueue.addFirst(value); + if(strongReferenceQueue.size() > strongReferenceSize) { + strongReferenceQueue.removeLast(); + } + } + return value; + } + + // Doesn't support this either + + public int hashCode() { + emptyQueue(); + throw new UnsupportedOperationException("SoftMap doesn't support hashCode"); + } + + // This is another risky method, since again, garbage collection is async + + public boolean isEmpty() { + emptyQueue(); + return map.isEmpty(); + } + + // Return all the keys, again could go out of date + + public Set keySet() { + emptyQueue(); + return map.keySet(); + } + + // Adds the mapping to the map + + public V put(K key, V value) { + emptyQueue(); + V old = fastGet(key); + fastPut(key, value); + return old; + } + + private void fastPut(K key, V value) { + map.put(key, new SoftMapReference<K,V>(key, value, queue)); + strongReferenceQueue.addFirst(value); + if(strongReferenceQueue.size() > strongReferenceSize) { + strongReferenceQueue.removeLast(); + } + } + + // Adds the mappings to the map + + public void putAll(Map other) { + emptyQueue(); + Iterator<K> itr = other.keySet().iterator(); + while(itr.hasNext()) { + K key = itr.next(); + fastPut(key, (V)other.get(key)); + } + } + + // Remove object + + public V remove(K key) { + emptyQueue(); + SoftMapReference<K,V> ref = map.remove(key); + if(ref != null) { + return ref.get(); + } + return null; + } + + // Returns size, could go out of date + + public int size() { + emptyQueue(); + return map.size(); + } + + // Shouldn't support this since it would create strong references to all the entries + + public Collection values() { + emptyQueue(); + throw new UnsupportedOperationException("SoftMap does not support this operation, since it creates potentially stong references"); + } + + + private static class SoftMapReference<K,V> extends SoftReference<V> { + K key; + + SoftMapReference(K key, V value, ReferenceQueue queue) { + super(value, queue); + this.key = key; + } + } + +} |