summaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
authorDinnerbone <dinnerbone@dinnerbone.com>2011-03-09 22:12:28 +0000
committerDinnerbone <dinnerbone@dinnerbone.com>2011-03-09 22:12:28 +0000
commit0df1d1a1011d16562e4d5d1d6fd60182a0508401 (patch)
treefece752d5aba07b62545d63fabc644cee2177c6c /src/main
parent507e2be8ea837aa06c33d158ccc25270b62d832a (diff)
downloadcraftbukkit-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/main')
-rw-r--r--src/main/java/org/bukkit/craftbukkit/CraftChunk.java3
-rw-r--r--src/main/java/org/bukkit/craftbukkit/util/SoftMap.java200
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;
+ }
+ }
+
+}