Added #1875 Remove no longer accessed items from cache after certain amount of time

This commit is contained in:
Jindra Petřík
2022-11-17 08:49:30 +01:00
parent 77a6b6a019
commit 202e66ea1d
12 changed files with 103 additions and 19 deletions

View File

@@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
### Added
- [#1870] AS3 Adding new class - Target DoABC tag or position can be selected to prevent Error 1014
- [#1871] Toogle buttons for disabling subsprite animation, display preview of sprites/frames
- [#1875] Remove no longer accessed items from cache after certain amount of time
### Fixed
- [#1869] Replace references now replaces all references, not just PlaceObject
@@ -2588,6 +2589,7 @@ All notable changes to this project will be documented in this file.
[alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7
[#1870]: https://www.free-decompiler.com/flash/issues/1870
[#1871]: https://www.free-decompiler.com/flash/issues/1871
[#1875]: https://www.free-decompiler.com/flash/issues/1875
[#1869]: https://www.free-decompiler.com/flash/issues/1869
[#1872]: https://www.free-decompiler.com/flash/issues/1872
[#1867]: https://www.free-decompiler.com/flash/issues/1867

View File

@@ -47,9 +47,9 @@ public class IdentifiersDeobfuscation {
private final HashMap<String, Integer> typeCounts = new HashMap<>();
private static final Cache<String, String> as2NameCache = Cache.getInstance(false, true, "as2_ident");
private static final Cache<String, String> as2NameCache = Cache.getInstance(false, true, "as2_ident", true);
private static final Cache<String, String> as3NameCache = Cache.getInstance(false, true, "as3_ident");
private static final Cache<String, String> as3NameCache = Cache.getInstance(false, true, "as3_ident", true);
public static final String VALID_FIRST_CHARACTERS = "\\p{Lu}\\p{Ll}\\p{Lt}\\p{Lm}\\p{Lo}_$";

View File

@@ -341,16 +341,16 @@ public final class SWF implements SWFContainerItem, Timelined {
private final IdentifiersDeobfuscation deobfuscation = new IdentifiersDeobfuscation();
@Internal
private final Cache<String, SerializableImage> frameCache = Cache.getInstance(false, false, "frame");
private final Cache<String, SerializableImage> frameCache = Cache.getInstance(false, false, "frame", true);
@Internal
private final Cache<CharacterTag, RECT> rectCache = Cache.getInstance(true, true, "rect");
private final Cache<CharacterTag, RECT> rectCache = Cache.getInstance(true, true, "rect", true);
@Internal
private final Cache<SHAPE, ShapeExportData> shapeExportDataCache = Cache.getInstance(true, true, "shapeExportData");
private final Cache<SHAPE, ShapeExportData> shapeExportDataCache = Cache.getInstance(true, true, "shapeExportData", true);
@Internal
private final Cache<SoundInfoSoundCacheEntry, byte[]> soundCache = Cache.getInstance(false, false, "sound");
private final Cache<SoundInfoSoundCacheEntry, byte[]> soundCache = Cache.getInstance(false, false, "sound", true);
@Internal
public final AS2Cache as2Cache = new AS2Cache();

View File

@@ -27,9 +27,9 @@ import com.jpexs.helpers.Cache;
*/
public class AS2Cache {
private final Cache<ASMSource, HighlightedText> cache = Cache.getInstance(true, false, "as2");
private final Cache<ASMSource, HighlightedText> cache = Cache.getInstance(true, false, "as2", false);
private final Cache<ASMSource, ActionList> pcodeCache = Cache.getInstance(true, true, "as2pcode");
private final Cache<ASMSource, ActionList> pcodeCache = Cache.getInstance(true, true, "as2pcode", false);
public void clear() {
pcodeCache.clear();

View File

@@ -26,7 +26,7 @@ import com.jpexs.helpers.Cache;
*/
public class AS3Cache {
private final Cache<ScriptPack, HighlightedText> cache = Cache.getInstance(true, false, "as3");
private final Cache<ScriptPack, HighlightedText> cache = Cache.getInstance(true, false, "as3", false);
public void clear() {
cache.clear();

View File

@@ -787,6 +787,10 @@ public final class Configuration {
@ConfigurationDefaultBoolean(true)
@ConfigurationCategory("display")
public static ConfigurationItem<Boolean> autoPlayPreviews = null;
@ConfigurationDefaultInt(5 * 60 * 1000)
@ConfigurationCategory("limit")
public static ConfigurationItem<Integer> maxCachedTime = null;
private enum OSId {
WINDOWS, OSX, UNIX

View File

@@ -31,7 +31,7 @@ import java.util.logging.Logger;
public class AbstractDocs {
protected static Cache<String, String> docsCache = Cache.getInstance(false, true, "abstractDocsCache");
protected static Cache<String, String> docsCache = Cache.getInstance(false, true, "abstractDocsCache", false);
protected static String htmlFooter() {
StringBuilder sb = new StringBuilder();

View File

@@ -16,6 +16,7 @@
*/
package com.jpexs.helpers;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.helpers.Freed;
import java.io.File;
import java.io.IOException;
@@ -27,6 +28,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
@@ -37,6 +40,7 @@ import java.util.WeakHashMap;
public class Cache<K, V> implements Freed {
private Map<K, V> cache;
private Map<K, Long> lastAccessed;
private static final List<WeakReference<Cache>> instances = new ArrayList<>();
@@ -49,6 +53,12 @@ public class Cache<K, V> implements Freed {
private final boolean memoryOnly;
private final String name;
private final boolean temporary;
private static final long CLEAN_INTERVAL = 5 * 1000; //5 seconds
private static Thread oldCleaner = null;
static {
Runtime.getRuntime().addShutdownHook(new Thread() {
@@ -67,8 +77,24 @@ public class Cache<K, V> implements Freed {
});
}
public static <K, V> Cache<K, V> getInstance(boolean weak, boolean memoryOnly, String name) {
Cache<K, V> instance = new Cache<>(weak, memoryOnly, name);
public static <K, V> Cache<K, V> getInstance(boolean weak, boolean memoryOnly, String name, boolean temporary) {
if (oldCleaner == null) {
oldCleaner = new Thread("Old cache cleaner") {
@Override
public void run() {
while(!Thread.interrupted()) {
try {
Thread.sleep(CLEAN_INTERVAL);
} catch (InterruptedException ex) {
return;
}
clearAllOld();
}
}
};
oldCleaner.start();
}
Cache<K, V> instance = new Cache<>(weak, memoryOnly, name, temporary);
instances.add(new WeakReference<>(instance));
return instance;
}
@@ -129,36 +155,48 @@ public class Cache<K, V> implements Freed {
if (this.cache instanceof Freed) {
((Freed) this.cache).free();
}
this.lastAccessed = new WeakHashMap<>();
this.cache = newCache;
}
private Cache(boolean weak, boolean memoryOnly, String name) {
private Cache(boolean weak, boolean memoryOnly, String name, boolean temporary) {
this.weak = weak;
this.name = name;
this.memoryOnly = memoryOnly;
this.temporary = temporary;
initCache();
}
public synchronized boolean contains(K key) {
return cache.containsKey(key);
public synchronized boolean contains(K key) {
boolean ret = cache.containsKey(key);
if (ret) {
lastAccessed.put(key, System.currentTimeMillis());
}
return ret;
}
public synchronized void clear() {
cache.clear();
lastAccessed.clear();
}
public synchronized void remove(K key) {
if (cache.containsKey(key)) {
cache.remove(key);
}
if (lastAccessed.containsKey(key)) {
lastAccessed.remove(key);
}
}
public synchronized V get(K key) {
lastAccessed.put(key, System.currentTimeMillis());
return cache.get(key);
}
public synchronized void put(K key, V value) {
cache.put(key, value);
lastAccessed.put(key, System.currentTimeMillis());
}
@Override
@@ -178,4 +216,37 @@ public class Cache<K, V> implements Freed {
ret.addAll(cache.keySet());
return ret;
}
private synchronized int clearOld() {
long currentTime = System.currentTimeMillis();
Set<K> keys = new HashSet<>(lastAccessed.keySet());
int temporaryThreshold = Configuration.maxCachedTime.get();
if (temporaryThreshold == 0) {
return 0;
}
int num = 0;
for(K key:keys) {
long time = lastAccessed.get(key);
if (time < currentTime - temporaryThreshold) {
remove(key);
num++;
}
}
return num;
}
private static void clearAllOld() {
int num = 0;
for (WeakReference<Cache> cw : instances) {
Cache c = cw.get();
if (c != null) {
if (c.temporary) {
num += c.clearOld();
}
}
}
if (num > 0) {
System.gc();
}
}
}

View File

@@ -99,7 +99,7 @@ public class FolderPreviewPanel extends JPanel {
public FolderPreviewPanel(final MainPanel mainPanel, List<TreeItem> items) {
this.items = items;
cachedPreviews = Cache.getInstance(false, false, "preview");
cachedPreviews = Cache.getInstance(false, false, "preview", true);
addMouseListener(new MouseAdapter() {
@Override

View File

@@ -150,7 +150,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay {
private final List<SoundTagPlayer> soundPlayers = new ArrayList<>();
private final Cache<DisplayObjectCacheKey, SerializableImage> displayObjectCache = Cache.getInstance(false, false, "displayObject");
private final Cache<DisplayObjectCacheKey, SerializableImage> displayObjectCache = Cache.getInstance(false, false, "displayObject", true);
private final IconPanel iconPanel;

View File

@@ -601,4 +601,8 @@ config.name.animateSubsprites = Animate subsprites in preview
config.description.allowMiterClipLinestyle = Allow subsprite animation on timeline preview.
config.name.autoPlayPreviews = Autoplay previews
config.description.autoPlayPreviews = Automatically play previews.
config.description.autoPlayPreviews = Automatically play previews.
config.name.maxCachedTime = Maximum temporary cache time
config.description.maxCachedTime = Maximum time in milliseconds before item (which was not accessed since) is removed from cache. Set this to 0 to unlimited caching.

View File

@@ -588,4 +588,7 @@ config.name.animateSubsprites = Animovat podsprity v n\u00e1hledu
config.description.allowMiterClipLinestyle = Povolit animace podsprit\u016f v n\u00e1hledu timeliny.
config.name.autoPlayPreviews = Automaticky p\u0159ehr\u00e1vat n\u00e1hledy
config.description.autoPlayPreviews = Automaticky p\u0159ehr\u00e1vat n\u00e1hledy.
config.description.autoPlayPreviews = Automaticky p\u0159ehr\u00e1vat n\u00e1hledy.
config.name.maxCachedTime = Maxim\u00e1ln\u00ed \u010das do\u010dasn\u00e9 cache
config.description.maxCachedTime = Maxim\u00e1ln\u00ed \u010das v milisekund\u00e1ch, kter\u00fd mus\u00ed ub\u011bhnout, aby byla polo\u017eka(kter\u00e1 nebyla mezit\u00edm aktivn\u00ed) odstran\u011bna z cache. Nastavte sem hodnotu 0 pro nekone\u010dn\u00e9 cachov\u00e1n\u00ed.