在我的代码中,我经常在服务器上运行,我无法控制配置,我有用户集合,每个用户都有一个byte[]
数组。
有时这些byte[]
数组对用户来说是唯一的。但是,通常会有大量用户使用完全相同的byte[]
数组。
我正在尝试减少服务器的RAM消耗。
我已经尝试将我的byte[]
数组转换为字符串并实习它们,但后来我经常遇到PERM-GEN内存不足错误。当我想为用户访问byte[]
数组时,我也发现编码/解码会显着降低性能,而且我看到更糟糕的内存使用情况 - 预备字符串比数组大得多。
当Java数组不可清除时,如何进行Set<SoftReference<byte[]>>
查找,而SoftReferences不会将对象的哈希包装在任何一点上。 Map<byte[],SoftReference<byte[]>>
显然也在打败自己,因为关键本身并阻止收集;无论如何,Set
内部实施了Map
。
那我怎么能实习生 byte[]
数组呢?
答案 0 :(得分:5)
如果您有效地拥有许多相同的数组,请使用HashSet<ByteBuffer>
作为缓存。您可以使用方法array()
获取ByteBuffer数组,并且ByteBuffer类具有hashCode
和equals
方法。当然,如果你的数组是不可变的,那就好了。
EDIT2 来自@Will的评论是准确的,为了能够取回数组,使用WeakHashMap<ByteBuffer,WeakReference<ByteBuffer>>
并执行类似的操作:
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();
}
答案 1 :(得分:2)
我已经尝试将我的byte []数组转换为字符串并实习它们,但之后我经常遇到PERM-GEN内存不足错误。
我同意您需要String.intern()
之类的内容,但标准实施方式为native
,所以没有多少乐趣。
您可以使用Map<Integer,Collection<SoftReference<byte[]>>>
,使用字节数组的哈希码作为Map
键。然后,您的intern
方法可以使用与给定字节数组相同的代码查找现有字节数组。使用一个好的哈希代码,它应该提供一小组数组来检查匹配。
修改:澄清:
这样的事情:
class ByteArrayCache
{
private final Map<Integer,Collection<SoftReference<byte[]>> map = new ...;
public final byte[] intern(byte[] byteArray)
{
final int hash = Arrays.hashCode(byteArray);
final Collection<SoftReference<byte[]>> arrays = map.get(hash);
if (arrays != null) {
// Search through arrays for a match, and return the match.
// If no match found, add byteArray to the collection and return it
} else {
// create a new map entry, add byteArray to it, and return byte array
}
}
}
答案 2 :(得分:1)
我会基于Guava弱值映射实现缓存。它保证如果没有对字节数组的强引用,则会自动删除该条目。
class Cache {
private final ConcurrentMap<Key, byte[]> map = new MapMaker().weakValues().makeMap();
private static class Key {
byte[] a;
int hash;
Key(byte[] a) {
this.a = a;
hash = Arrays.hashCode(a);
}
@Override
public int hashCode() {
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Key) {
return Arrays.equals(a, ((Key) obj).a);
}
return false;
}
}
public byte[] intern(byte[] a) {
byte[] a1 = map.putIfAbsent(new Key(a), a);
if (a1 != null) {
return a1;
}
return a;
}
}