Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

creating a cache of byte arrays

In my code, which often runs on servers I do not control the configuration of, I have collection of users and each user has a byte[] array.

Sometimes these byte[] arrays are unique to the user. Often, though, there will be large numbers users with the exact same byte[] array.

I am trying to reduce the RAM consumption of my server.

I've tried turning my byte[] arrays into strings and interning them, but then I often run into PERM-GEN out-of-memory errors. I also see a significant performance degradation with the encoding/decoding when I want to access the byte[] array for a user, and I see much increased worse-case memory usage - presuambly strings are much larger than arrays.

How can I have a Set<SoftReference<byte[]>> lookup when Java arrays are not hashable and SoftReferences do not wrap the hash of the object the point at either. A Map<byte[],SoftReference<byte[]>> is obviously also defeating itself because the key is itself and prevents collection; and Set is internally implemented in terms of Mapanyway.

So how can I intern byte[] arrays?

like image 933
Will Avatar asked Jun 12 '13 12:06

Will


1 Answers

If you effectively have many identical arrays, use an HashSet<ByteBuffer> as a cache. You can get the ByteBuffer array with method array() and the ByteBuffer class has hashCode and equals methods. Of course it is better if your arrays are immutable.

EDIT2 The comment from @Will is exact, to be able to get back the array, use a WeakHashMap<ByteBuffer,WeakReference<ByteBuffer>> and do something like that :

public byte[] internalize(byte[] bytes) {
 ByteBuffer wrapped = ByteBuffer.wrap(bytes);
 if(cache.containsKey(wrapped)) {
  wrapped = cache.get(wrapped).get();
 }
 else {
  cache.put(wrapped, new WeakReference<ByteBuffer>(wrapped);
 }
 return wrapped.array();
}
like image 169
gma Avatar answered Oct 25 '22 11:10

gma