2013-06-12 48 views
14

Trong mã của tôi, thường chạy trên máy chủ, tôi không kiểm soát cấu hình, tôi có bộ sưu tập người dùng và mỗi người dùng có một mảng byte[].tạo bộ nhớ cache của mảng byte

Đôi khi các mảng byte[] này là duy nhất cho người dùng. Thông thường, mặc dù, sẽ có số lượng người dùng lớn với cùng một mảng byte[].

Tôi đang cố giảm mức tiêu thụ RAM của máy chủ.

Tôi đã thử biến các mảng byte[] thành chuỗi và thực hiện chúng, nhưng sau đó tôi thường gặp phải lỗi ngoài bộ nhớ PERM-GEN. Tôi cũng thấy một sự suy giảm hiệu suất đáng kể với mã hóa/giải mã khi tôi muốn truy cập mảng byte[] cho người dùng và tôi thấy việc sử dụng bộ nhớ có mức độ tệ hơn nhiều - các chuỗi presuambly lớn hơn nhiều so với mảng.

Làm cách nào tôi có thể tra cứu Set<SoftReference<byte[]>> khi mảng Java không được băm và SoftReferences không bao hàm giá trị băm của đối tượng tại một trong hai điểm. Một Map<byte[],SoftReference<byte[]>> rõ ràng là cũng đánh bại chính nó bởi vì chính là chính nó và ngăn cản việc thu thập; và Set được triển khai nội bộ theo số Map.

Vậy làm cách nào tôi có thể thực tậpbyte[] mảng?

+0

Một điều bạn nghĩ đến là mô hình Flyweight. Ngoài ra, hãy xem http://stackoverflow.com/questions/1058149/using-a-byte-array-as-hashmap-key-java –

+0

Tôi nghĩ bạn sẽ phải bao bọc các mảng byte của mình, đánh đấm chúng hiệu quả, ví dụ: với 'ByteArray mới (byte [] theBytes)' và không bao giờ thực hiện các tham chiếu dài hạn bổ sung cho 'theBytes' bên ngoài chính' ByteArray'. Sau đó, các tham chiếu mềm tới 'ByteArray' sẽ hoạt động chính xác. Bạn cũng có thể xem 'WeakHashMap 'cho ứng dụng của bạn. – Gene

+0

Các mảng byte này lớn đến mức nào? Làm thế nào để người dùng có được một? – fge

Trả lời

5

Nếu bạn có nhiều mảng giống hệt nhau, hãy sử dụng một bộ nhớ cache HashSet<ByteBuffer>. Bạn có thể nhận mảng ByteBuffer với phương thức array() và lớp ByteBuffer có các phương thức hashCodeequals. Tất nhiên nó là tốt hơn nếu mảng của bạn là không thay đổi.

EDIT2 Các bình luận từ @ Will là chính xác, để có thể trở lại mảng, sử dụng một WeakHashMap<ByteBuffer,WeakReference<ByteBuffer>> và làm điều gì đó như thế:

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(); 
} 
+0

Làm cách nào để tôi thu thập chúng từ bộ nhớ cache khi hệ thống cần bộ nhớ và không có người dùng nào tham khảo chúng? – Will

+0

@Will: Xem chỉnh sửa của tôi – gma

+1

Một 'WeakHashMap ' có thể truyền đạt ý định rõ ràng hơn. Bạn có thể lưu trữ các giá trị rỗng như các giá trị. –

2

Tôi đã thử chuyển byte của tôi [ ] mảng thành chuỗi và thực hiện chúng, nhưng sau đó tôi thường chạy vào các lỗi ngoài bộ nhớ PERM-GEN.

Tôi đồng ý rằng bạn cần một cái gì đó như String.intern(), nhưng việc triển khai chuẩn là native, vì vậy không có nhiều niềm vui.

Bạn có thể có một Map<Integer,Collection<SoftReference<byte[]>>>, sử dụng mã băm của mảng byte làm khóa Map. Phương pháp intern của bạn sau đó có thể tra cứu tập hợp các mảng byte hiện có với cùng một mã có các mảng byte đã cho. Với một mã băm tốt nên cung cấp cho một bộ nhỏ của mảng để kiểm tra cho một trận đấu.


Chỉnh sửa: Để làm rõ:

Something như thế này:

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 
      } 
     } 
} 
+0

Làm thế nào tôi có thể hút chân không mồ côi 'Integer' và' Set' khi chúng không được sử dụng? Và chi phí RAM của boxing quá nhiều trong trường hợp xấu nhất khi không có nhiều sự trùng lặp? – Will

+0

Nếu mảng lớn và thưa thớt, byte đầu tiên của md5 có thể là một hàm băm hữu ích. Nếu họ là nhỏ, cuộn-bạn sở hữu có thể sẽ đủ. – tucuxi

+0

@tucuxi 'Arrays.hashCode (byte [])' để giải cứu :) Nhưng vấn đề gây quỹ là bạn không thể phân lớp 'byte []' để vá rằng trong – Will

1

tôi sẽ thực hiện một bộ nhớ cache dựa trên Ổi bản đồ giá trị yếu. Nó đảm bảo rằng nếu không có tham chiếu mạnh mẽ hơn đến mảng byte, mục nhập sẽ tự động bị xóa.

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; 
    } 
} 
Các vấn đề liên quan