{"record":{"id":"98e2515390a78835","repo":"nostra13/Android-Universal-Image-Loader","slug":"classname-sizeof-is-reporting-inconsistent-res","errorCode":null,"errorMessage":"{className}.sizeOf() is reporting inconsistent results!","messagePattern":"(.+?)\\.sizeOf\\(\\) is reporting inconsistent results!","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/LruMemoryCache.java","lineNumber":84,"sourceCode":"\t\t\t}\n\t\t}\n\n\t\ttrimToSize(maxSize);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Remove the eldest entries until the total of remaining entries is at or below the requested size.\n\t *\n\t * @param maxSize the maximum size of the cache before returning. May be -1 to evict even 0-sized elements.\n\t */\n\tprivate void trimToSize(int maxSize) {\n\t\twhile (true) {\n\t\t\tString key;\n\t\t\tBitmap value;\n\t\t\tsynchronized (this) {\n\t\t\t\tif (size < 0 || (map.isEmpty() && size != 0)) {\n\t\t\t\t\tthrow new IllegalStateException(getClass().getName() + \".sizeOf() is reporting inconsistent results!\");\n\t\t\t\t}\n\n\t\t\t\tif (size <= maxSize || map.isEmpty()) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tMap.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next();\n\t\t\t\tif (toEvict == null) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tkey = toEvict.getKey();\n\t\t\t\tvalue = toEvict.getValue();\n\t\t\t\tmap.remove(key);\n\t\t\t\tsize -= sizeOf(key, value);\n\t\t\t}\n\t\t}\n\t}\n","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/nostra13/Android-Universal-Image-Loader/blob/ba33ec64d0daaa881d35852460e78c58d086bc18/library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/LruMemoryCache.java#L66-L102","documentation":"LruMemoryCache.trimToSize throws IllegalStateException when its internal size counter goes negative or disagrees with map emptiness (map empty but size != 0). The counter is maintained by sizeOf(key, bitmap) during put/remove/evict; inconsistency means sizeOf returned different values for the same bitmap at different times. This class's sizeOf is fixed (bitmap.getRowBytes() * bitmap.getHeight()), so this error in stock UIL indicates concurrent corruption or a subclass with a non-deterministic sizeOf.","triggerScenarios":"Subclassing LruMemoryCache and overriding sizeOf() with a value that changes between insert and eviction (e.g. depends on mutable state, or returns the bitmap's current byte size after the bitmap was recycled); calling bitmap.recycle() on cached bitmaps so later sizeOf calls return different values; reflective/unsynchronized access from multiple threads despite the synchronized blocks.","commonSituations":"Custom memory caches extending LruMemoryCache with per-entry soft references or compressed sizes; an aggressive bitmap-recycling strategy recycling bitmaps still in the cache; bugs where getMemoryCache() is replaced while tasks are in flight.","solutions":["If overriding sizeOf(), make it deterministic and stable for the lifetime of the entry (compute once, never change)","Do not recycle bitmaps while they are still cached; let the LRU evict them","If it happens without subclassing, look for thread-unsafe external mutation of the map (e.g. via iterator from another thread) and route all access through the cache API"],"exampleFix":"// before\nclass MyCache extends LruMemoryCache {\n    @Override\n    protected int sizeOf(String key, Bitmap value) {\n        return value.getAllocationByteCount() - compressed.get(key); // varies over time\n    }\n}\n\n// after\nclass MyCache extends LruMemoryCache {\n    @Override\n    protected int sizeOf(String key, Bitmap value) {\n        return value.getRowBytes() * value.getHeight(); // stable for the entry lifetime\n    }\n}","handlingStrategy":"validation","validationCode":"// If you subclass LruMemoryCache, verify sizeOf stability:\n// insert, read sizeOf twice, assert equal\nBitmap b = decode(uri);\nint s1 = cache.sizeOf(uri, b);\nint s2 = cache.sizeOf(uri, b);\nassert s1 == s2 && s1 >= 0 : \"sizeOf must be deterministic\";","typeGuard":null,"tryCatchPattern":"try {\n    cache.put(uri, bitmap);\n} catch (IllegalStateException e) {\n    // accounting corrupted: clear and rebuild\n    cache.clear();\n    cache.put(uri, bitmap);\n}","preventionTips":["Keep sizeOf() a pure function of the entry (rowBytes * height), never of mutable state","Never recycle cached bitmaps; only recycle after eviction","Do not subclass LruMemoryCache unless sizeOf determinism is guaranteed"],"tags":["memory-cache","lru","invariant","subclassing","bitmap-lifecycle"],"backgroundTag":null,"analyzedSha":"ba33ec64d0daaa881d35852460e78c58d086bc18","analyzedAt":"2026-08-14T15:41:15.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}