mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-03 13:36:44 +01:00
Changed block cache to soft references (should help a lot with memory usage)
This commit is contained in:
parent
507e2be8ea
commit
0df1d1a101
2 changed files with 202 additions and 1 deletions
|
@ -10,10 +10,11 @@ import org.bukkit.Chunk;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.craftbukkit.block.CraftBlock;
|
import org.bukkit.craftbukkit.block.CraftBlock;
|
||||||
|
import org.bukkit.craftbukkit.util.SoftMap;
|
||||||
|
|
||||||
public class CraftChunk implements Chunk {
|
public class CraftChunk implements Chunk {
|
||||||
private WeakReference<net.minecraft.server.Chunk> weakChunk;
|
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 WorldServer worldServer;
|
||||||
private int x;
|
private int x;
|
||||||
private int z;
|
private int z;
|
||||||
|
|
200
src/main/java/org/bukkit/craftbukkit/util/SoftMap.java
Normal file
200
src/main/java/org/bukkit/craftbukkit/util/SoftMap.java
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue