diff --git a/core/java/src/net/i2p/data/ByteArray.java b/core/java/src/net/i2p/data/ByteArray.java index 9f460fe475..d013809c8e 100644 --- a/core/java/src/net/i2p/data/ByteArray.java +++ b/core/java/src/net/i2p/data/ByteArray.java @@ -24,11 +24,21 @@ public class ByteArray implements Serializable, Comparable { public ByteArray() { } - /** Sets valid */ + /** + * Sets valid = data.length, unless data is null + * Sets offset = 0 + * @param data may be null + */ public ByteArray(byte[] data) { _data = data; _valid = (data != null ? data.length : 0); } + + /** + * Sets offset = offset + * Sets valid = length + * @param data may be null but why would you do that + */ public ByteArray(byte[] data, int offset, int length) { _data = data; _offset = offset; diff --git a/core/java/src/net/i2p/util/ByteCache.java b/core/java/src/net/i2p/util/ByteCache.java index 7253a472e8..b88a21c141 100644 --- a/core/java/src/net/i2p/util/ByteCache.java +++ b/core/java/src/net/i2p/util/ByteCache.java @@ -16,7 +16,7 @@ import net.i2p.data.ByteArray; * For small arrays where the management of valid bytes in ByteArray * and prezeroing isn't required, use SimpleByteArray instead. * - * Heap size control - survey of usage (April 2010) : + * Heap size control - survey of usage: * *
 	Size	Max	MaxMem	From
@@ -34,6 +34,8 @@ import net.i2p.data.ByteArray;
 
 	8K	8	64K	I2PTunnel HTTPResponseOutputStream
 
+	16K	16	256K	I2PSnark
+
 	32K	4	128K	SAM StreamSession
 	32K	10	320K	SAM v2StreamSession
 	32K	64	2M	UDP OMS
@@ -67,7 +69,10 @@ public final class ByteCache {
     }
 
     /**
-     * Get a cache responsible for objects of the given size
+     * Get a cache responsible for objects of the given size.
+     * Warning, if you store the result in a static field, the cleaners will
+     * not operate after a restart on Android, as the old context's SimpleScheduler will have shut down.
+     * TODO tie this to the context or clean up all calls.
      *
      * @param cacheSize how large we want the cache to grow 
      *                  (number of objects, NOT memory size)
@@ -103,7 +108,7 @@ public final class ByteCache {
     /** list of available and available entries */
     private Queue _available;
     private int _maxCached;
-    private int _entrySize;
+    private final int _entrySize;
     private long _lastOverflow;
     
     /** do we actually want to cache? Warning - setting to false may NPE, this should be fixed or removed */
@@ -120,7 +125,7 @@ public final class ByteCache {
         _maxCached = maxCachedEntries;
         _entrySize = entrySize;
         _lastOverflow = -1;
-        SimpleScheduler.getInstance().addPeriodicEvent(new Cleanup(), CLEANUP_FREQUENCY + (entrySize % 7));   //stagger
+        SimpleScheduler.getInstance().addPeriodicEvent(new Cleanup(), CLEANUP_FREQUENCY + (entrySize % 777));   //stagger
         I2PAppContext.getGlobalContext().statManager().createRateStat("byteCache.memory." + entrySize, "Memory usage (B)", "Router", new long[] { 10*60*1000 });
     }
     
@@ -136,8 +141,11 @@ public final class ByteCache {
     }
     
     /**
-     * Get the next available structure, either from the cache or a brand new one
-     *
+     * Get the next available structure, either from the cache or a brand new one.
+     * Returned ByteArray will have valid = 0 and offset = 0.
+     * Returned ByteArray may or may not be zero, depends on whether
+     * release(ba) or release(ba, false) was called.
+     * Which is a problem, you should really specify shouldZero on acquire, not release.
      */
     public final ByteArray acquire() {
         if (_cache) {
@@ -149,7 +157,7 @@ public final class ByteCache {
         byte data[] = new byte[_entrySize];
         ByteArray rv = new ByteArray(data);
         rv.setValid(0);
-        rv.setOffset(0);
+        //rv.setOffset(0);
         return rv;
     }
     
@@ -160,11 +168,17 @@ public final class ByteCache {
     public final void release(ByteArray entry) {
         release(entry, true);
     }
+
     public final void release(ByteArray entry, boolean shouldZero) {
         if (_cache) {
-            if ( (entry == null) || (entry.getData() == null) )
+            if (entry == null || entry.getData() == null)
                 return;
-            
+            if (entry.getData().length != _entrySize) {
+                Log log = I2PAppContext.getGlobalContext().logManager().getLog(ByteCache.class);
+                if (log.shouldLog(Log.WARN))
+                    log.warn("Bad size", new Exception("I did it"));
+                return;
+            }
             entry.setValid(0);
             entry.setOffset(0);