14

在我的代码中,通常在我不控制配置的服务器上运行,我有用户集合,每个用户都有一个byte[]数组。

有时这些byte[]数组对用户来说是唯一的。但是,通常会有大量用户使用完全相同的byte[]数组。

我正在尝试减少服务器的 RAM 消耗。

我尝试将我的byte[]数组转换为字符串并将它们实习,但我经常遇到PERM-GEN 内存不足错误。当我想为用户访问数组时,我还看到编码/解码的性能显着下降byte[],并且我看到更坏情况下的内存使用量大大增加 - 可能字符串比数组大得多。

Set<SoftReference<byte[]>>当 Java 数组不可散列并且 SoftReferences 不包装对象的散列点时,我如何进行查找。AMap<byte[],SoftReference<byte[]>>显然也在打败自己,因为关键是它自己并且阻止了收集;并且无论如何Set都是在内部实现的。Map

那么我怎样才能实习 byte[]数组呢?

4

3 回答 3

5

如果您实际上有许多相同的数组,请使用 anHashSet<ByteBuffer>作为缓存。您可以使用方法获取 ByteBuffer 数组,array()而 ByteBuffer 类具有hashCodeequals方法。当然,如果您的数组是不可变的,那就更好了。

EDIT2 @Will 的评论是准确的,为了能够取回数组,使用 aWeakHashMap<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();
}
于 2013-06-12T12:28:37.623 回答
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
           }
      }
 }
于 2013-06-12T12:29:42.393 回答
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;
    }
}
于 2013-06-12T12:43:57.723 回答