Note that there are some explanatory texts on larger screens.

plurals
  1. POUsing MapMaker to create a cache
    primarykey
    data
    text
    <p>I want to use MapMaker to create a map that caches large objects, which should be removed from the cache if there is not enough memory. This little demo program seems to work fine:</p> <pre><code>public class TestValue { private final int id; private final int[] data = new int[100000]; public TestValue(int id) { this.id = id; } @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("finalized"); } } public class Main { private ConcurrentMap&lt;Integer, TestValue&gt; cache; MemoryMXBean memoryBean; public Main() { cache = new MapMaker() .weakKeys() .softValues() .makeMap(); memoryBean = ManagementFactory.getMemoryMXBean(); } public void test() { int i = 0; while (true) { System.out.println("Etntries: " + cache.size() + " heap: " + memoryBean.getHeapMemoryUsage() + " non-heap: " + memoryBean.getNonHeapMemoryUsage()); for (int j = 0; j &lt; 10; j++) { i++; TestValue t = new TestValue(i); cache.put(i, t); } try { Thread.sleep(100); } catch (InterruptedException ex) { } } } /** * @param args the command line arguments */ public static void main(String[] args) { Main m = new Main(); m.test(); } } </code></pre> <p>However, when I do the same thing in my real application, entries are basically removed from the cache as soon as they are added. In my real application, I also use integers as keys, and the cached values are archive blocks read from disk that contains some data. As far as I understand, weak-references are garbage-collected as soon as they are no longer used, so this seems to make sense because the keys are weak references. If I create the map like this:</p> <pre><code> data = new MapMaker() .softValues() .makeMap(); </code></pre> <p>The entries are never garbage-collected and I get an out-of-memory error in my test program. The finalize method on the TestValue entries is never called. If I change the test method to the following:</p> <pre><code>public void test() { int i = 0; while (true) { for (final Entry&lt;Integer, TestValue&gt; entry : data.entrySet()) { if (entry.getValue() == null) { data.remove(entry.getKey()); } } System.out.println("Etntries: " + data.size() + " heap: " + memoryBean.getHeapMemoryUsage() + " non-heap: " + memoryBean.getNonHeapMemoryUsage()); for (int j = 0; j &lt; 10; j++) { i++; TestValue t = new TestValue(i); data.put(i, t); } try { Thread.sleep(100); } catch (InterruptedException ex) { } } } </code></pre> <p>entries are removed from the cache and the finalizer on the TestValue objects is called, but after a while I also get an out-of-memory error.</p> <p>So my question is: what is the right way to use MapMaker to create a map that can be used as a cache? Why does my test program not remove the entries as soon as possible if I use weakKeys? Is it possible to add a reference queue to the cache map? </p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload