/** forces all soft references to be cleared by trying to allocate an enormous chunk of memory, * returns a description of what was done * (tune with {@link #forceClearSoftReferences(long, int)} * for greater than 200M precision in the output message, if you really care about that) */ public static String forceClearSoftReferences() { return forceClearSoftReferences(1000*1000, Integer.MAX_VALUE); } /** as {@link #forceClearSoftReferences()} but gives control over headroom and max chunk size.
@Override public void run() { long totalMemory = Runtime.getRuntime().totalMemory(); long freeMemory = Runtime.getRuntime().freeMemory(); long usedMemory = totalMemory - freeMemory; assertLessThan(MemoryUsageTracker.SOFT_REFERENCES.getBytesUsed(), maxMemory); assertLessThan(MemoryUsageTracker.SOFT_REFERENCES.getBytesUsed(), totalMemory); assertLessThan(MemoryUsageTracker.SOFT_REFERENCES.getBytesUsed(), usedMemory); }}); }
byte d[] = new byte[ALLOCATION_CHUNK_SIZE]; references.add(Maybe.soft(d)); MemoryUsageTracker.SOFT_REFERENCES.track(d, d.length); created += d.length; " ... in use: "+Strings.makeSizeString(totalMemory - freeMemory)+" / " + Strings.makeSizeString(totalMemory) + " ... reclaimable: "+Strings.makeSizeString(MemoryUsageTracker.SOFT_REFERENCES.getBytesUsed()) + " ... live refs: "+Strings.makeSizeString(sizeOfActiveReferences(references)) + " ... maxMem="+maxMemory+"; totalMem="+totalMemory+"; usedMem="+(totalMemory-freeMemory));
/** creates a tag suitable for marking a stream available on a task, but which might be GC'd */ public static WrappedStream tagForStreamSoft(String streamType, ByteArrayOutputStream stream) { MemoryUsageTracker.SOFT_REFERENCES.track(stream, stream.size()); Maybe<ByteArrayOutputStream> weakStream = Maybe.softThen(stream, STREAM_GARBAGE_COLLECTED_MAYBE); return new WrappedStream(streamType, Suppliers.compose(Functions.toStringFunction(), weakStream), Suppliers.compose(Streams.sizeFunction(), weakStream)); }
protected void forceGc() { MemoryUsageTracker.forceClearSoftReferences(); System.gc(); System.gc(); }
/** force a round of Brooklyn garbage collection */ public void gcIteration() { try { logUsage("brooklyn gc (before)"); gcTasks(); logUsage("brooklyn gc (after)"); double memUsage = 1.0 - 1.0*Runtime.getRuntime().freeMemory() / Runtime.getRuntime().maxMemory(); if (memUsage > brooklynProperties.getConfig(FORCE_CLEAR_SOFT_REFERENCES_ON_MEMORY_USAGE_LEVEL)) { LOG.info("Forcing brooklyn gc including soft-reference cleansing due to memory usage: "+getUsageString()); MemoryUsageTracker.forceClearSoftReferences(); System.gc(); System.gc(); LOG.info("Forced cleansing brooklyn gc, usage now: "+getUsageString()); } else if (brooklynProperties.getConfig(DO_SYSTEM_GC)) { // Can be very useful when tracking down OOMEs etc, where a lot of tasks are executing // Empirically observed that (on OS X jvm at least) calling twice blocks - logs a significant // amount of memory having been released, as though a full-gc had been run. But this is highly // dependent on the JVM implementation. System.gc(); System.gc(); logUsage("brooklyn gc (after system gc)"); } } catch (Throwable t) { Exceptions.propagateIfFatal(t); LOG.warn("Error during management-context GC: "+t, t); } }
String clearanceResult = MemoryUsageTracker.forceClearSoftReferences(100*1000, 10*1000*1000); LOG.info("Forcing memory eviction: " + clearanceResult);