nostra13/Android-Universal-Image-Loader · critical · IllegalStateException
{className}.sizeOf() is reporting inconsistent results!
Error message
{className}.sizeOf() is reporting inconsistent results! What it means
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.
Source
Thrown at library/src/main/java/com/nostra13/universalimageloader/cache/memory/impl/LruMemoryCache.java:84
}
}
trimToSize(maxSize);
return true;
}
/**
* Remove the eldest entries until the total of remaining entries is at or below the requested size.
*
* @param maxSize the maximum size of the cache before returning. May be -1 to evict even 0-sized elements.
*/
private void trimToSize(int maxSize) {
while (true) {
String key;
Bitmap value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");
}
if (size <= maxSize || map.isEmpty()) {
break;
}
Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next();
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= sizeOf(key, value);
}
}
}
View on GitHub (pinned to ba33ec64d0)
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
Example fix
// before
class MyCache extends LruMemoryCache {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getAllocationByteCount() - compressed.get(key); // varies over time
}
}
// after
class MyCache extends LruMemoryCache {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight(); // stable for the entry lifetime
}
} Defensive patterns
Strategy: validation
Validate before calling
// If you subclass LruMemoryCache, verify sizeOf stability: // insert, read sizeOf twice, assert equal Bitmap b = decode(uri); int s1 = cache.sizeOf(uri, b); int s2 = cache.sizeOf(uri, b); assert s1 == s2 && s1 >= 0 : "sizeOf must be deterministic";
Try / catch
try {
cache.put(uri, bitmap);
} catch (IllegalStateException e) {
// accounting corrupted: clear and rebuild
cache.clear();
cache.put(uri, bitmap);
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- maxSize <= 0
- maxSize <= 0
- maxFileCount <= 0
- valueCount <= 0
- unexpected journal header: [{magic}, {version}, {valueCountS
AI-assisted analysis of nostra13/Android-Universal-Image-Loader@ba33ec64d0 (2026-08-14).
Data as JSON: /api/errors/98e2515390a78835.
Report an issue: GitHub.