Jim, > > I made an initial stab at a prototype of some cache management classes that I think might aid in maintenance: > > http://cr.openjdk.java.net/~flar/MarlinArrayCaches/webrev.00/ >
Your prototype is interesting and I better understand your design. However, I had no time yet to play with it: sorry ! Few general comments: - cached arrays should be wrapped by a WeakReference to reduce the memory footprint => create few XXXArrayGrowthCache instances and wrap the internal arrays[][] with a Weak Reference (as I did in the RendererContext) - share caches between use cases: reuse a IntArrayGrowthCache instance (3 caches for now) shared among use cases: - introduce references to keep initial arrays: use a CacheReference(IntArrayGrowthCache, initial size) that wraps the cache methods and deal efficiently with initial arrays. As soon as I have some time, I could try adapting your prototype. Few comments: > - No use of Refs anywhere, TBD > - No attempts to share the base array buckets between multiple caches. OK, I will try or you prefer to do it ? > - DO_CLEAN_DIRTY and STATS are both handled via delegating wrappers which means they can be present in production code and enabled by a command line variable at runtime with absolutely no performance impact if they aren't used. OK. I adopted static flags as hotspot is able to remove "dead" / "unused code" => dynamic vs static optimization. > - The widen/put interface is common between the Clean and Dirty caches - I did that for simplicity, but in reality you pass in more information to the "Clean" version of those methods in your static methods so we should fix that up. It will likely require different method signatures, and therefore less implementation sharing, between the Clean/Dirty caches, but that is fine if it saves having to clear data unnecessarily. This would also mean that the wrappers for STATS and DO_CLEAN_DIRTY will also need to be duplicated for both variants as well. Of course, it remains to be fixed. > - The Int/Float versions of the classes can be auto-generated from the Byte versions with a sed script (included). Excellent. I did the same in the past ! > I'm envisioning these getting used something like: > > MarlinConst: > public CacheGrowthStrategy defaultStrategy = new ExponentialGrowthStrategy(...); > > Renderer: > private IntArrayGrowthSource edgeCache = > IntArrayGrowthCache.getDirtyInstance(defaultStrategy, "Edge Array"); => I would introduce 4 shared ArrayGrowthSource (Clean Int, Dirty Int, Dirty Float and Dirty Byte) in the RendererContext (thread context) accessible and provide few CacheReference helpers: private IntArrayGrowthSource edgeCacheRef = RendererContext.getCleanIntCacheRef(initialSize, "Edge Array"); This CacheReference class handles both the default array (initialSize capacity as I did) and hides the complexity of the proper and shared Cache usage. > ... > // No STAT or CLEAN_DIRTY code needed > edges = edgeCache.getDefaultArray(); > ... > // No STAT or CLEAN_DIRTY code needed > edges = edgeCache.widen(edges, numused, newsize); > ... > // No STAT or CLEAN_DIRTY code needed > edgeCache.putArray(edges); > edges = null; I looks good and is worth to try soon your new approach. Thanks for your work, Laurent