mirror of https://github.com/FreeCol/freecol.git
Automatically frees the low-priority-cache when memory runs out.
This commit is contained in:
parent
91a8055e2f
commit
da05dbdb5e
|
@ -21,6 +21,8 @@ package net.sf.freecol.common.resources;
|
|||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
@ -37,13 +39,15 @@ public class ImageCache {
|
|||
|
||||
private static final Logger logger = Logger.getLogger(ImageCache.class.getName());
|
||||
|
||||
private static final boolean DEBUG_PRINT_CACHE_SIZES_TO_STDOUT = false;
|
||||
private static final boolean DEBUG_PRINT_CACHE_SIZES_TO_STDOUT = true;
|
||||
|
||||
public static final String REPLACEMENT_IMAGE = "image.miscicon.delete";
|
||||
|
||||
/** A cache of scaled (and possibly greyed) images. */
|
||||
private final Map<Long, BufferedImage> cache;
|
||||
private final Map<Long, BufferedImage> lowPriorityCache;
|
||||
private final Map<Long, CacheSoftReference<Long, BufferedImage>> lowPriorityCache;
|
||||
private final ReferenceQueue<BufferedImage> lowPriorityCacheReferenceQueue = new ReferenceQueue<>();
|
||||
private final CacheCleanupThread cleanupThread = new CacheCleanupThread();
|
||||
|
||||
private long cacheSize = 0;
|
||||
private long lowPriorityCacheSize = 0;
|
||||
|
@ -55,6 +59,8 @@ public class ImageCache {
|
|||
public ImageCache() {
|
||||
this.cache = new HashMap<>();
|
||||
this.lowPriorityCache = new HashMap<>();
|
||||
|
||||
cleanupThread.start();
|
||||
}
|
||||
|
||||
|
||||
|
@ -167,13 +173,18 @@ public class ImageCache {
|
|||
if (image != null) {
|
||||
return image;
|
||||
}
|
||||
image = this.lowPriorityCache.get(cacheKey);
|
||||
image = getFromLowPriorityCache(cacheKey);
|
||||
if (image != null) {
|
||||
return image;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private BufferedImage getFromLowPriorityCache(long cacheKey) {
|
||||
final SoftReference<BufferedImage> ref = this.lowPriorityCache.get(cacheKey);
|
||||
return (ref != null) ? ref.get() : null;
|
||||
}
|
||||
|
||||
private void placeImageInCache(long hashKey, BufferedImage image) {
|
||||
if (image != null) {
|
||||
this.cache.put(hashKey, image);
|
||||
|
@ -184,8 +195,10 @@ public class ImageCache {
|
|||
|
||||
private void placeImageInLowPriorityCache(long hashKey, BufferedImage image) {
|
||||
if (image != null) {
|
||||
this.lowPriorityCache.put(hashKey, image);
|
||||
lowPriorityCacheSize += image.getWidth() * image.getHeight() * 4;
|
||||
final long size = image.getWidth() * image.getHeight() * 4;
|
||||
final CacheSoftReference<Long, BufferedImage> ref = new CacheSoftReference<>(hashKey, size, image, lowPriorityCacheReferenceQueue);
|
||||
this.lowPriorityCache.put(hashKey, ref);
|
||||
lowPriorityCacheSize += size;
|
||||
debugPrintCacheSizes();
|
||||
}
|
||||
}
|
||||
|
@ -273,4 +286,41 @@ public class ImageCache {
|
|||
this.lowPriorityCache.clear();
|
||||
this.lowPriorityCacheSize = 0;
|
||||
}
|
||||
|
||||
private final class CacheCleanupThread extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final CacheSoftReference<Long,BufferedImage> ref = (CacheSoftReference<Long,BufferedImage>) lowPriorityCacheReferenceQueue.remove();
|
||||
if (ref == null) {
|
||||
continue;
|
||||
}
|
||||
lowPriorityCacheSize -= ref.getSize();
|
||||
lowPriorityCache.remove(ref.getKey());
|
||||
}
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
private final class CacheSoftReference<K, V> extends SoftReference<V> {
|
||||
|
||||
private final K key;
|
||||
private final long size;
|
||||
|
||||
public CacheSoftReference(K key, long size, V referent, ReferenceQueue<? super V> q) {
|
||||
super(referent, q);
|
||||
this.key = key;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue