|
1 | 1 | package xerial.larray.buffer; |
2 | 2 |
|
3 | | -import org.slf4j.Logger; |
4 | | -import org.slf4j.LoggerFactory; |
| 3 | + |
| 4 | +import org.xerial.util.log.Logger; |
5 | 5 |
|
6 | 6 | import java.lang.ref.ReferenceQueue; |
7 | 7 | import java.util.Map; |
8 | 8 | import java.util.concurrent.ConcurrentHashMap; |
9 | 9 | import java.util.concurrent.atomic.AtomicLong; |
10 | 10 |
|
11 | | -import static xerial.larray.buffer.UnsafeUtil.unsafe; |
12 | | - |
13 | | - |
14 | | -/** |
15 | | - * Stores |(memory size:long)| data ... | |
16 | | - */ |
17 | | -class OffHeapMemory implements Memory { |
18 | | - |
19 | | - private final long _data; |
20 | | - |
21 | | - public static long HEADER_SIZE = 8L; |
22 | | - |
23 | | - /** |
24 | | - * Create an empty memory |
25 | | - */ |
26 | | - public OffHeapMemory() { |
27 | | - this._data = 0L; |
28 | | - } |
29 | | - |
30 | | - public OffHeapMemory(long address) { |
31 | | - if(address != 0L) |
32 | | - this._data = address + HEADER_SIZE; |
33 | | - else |
34 | | - this._data = 0L; |
35 | | - } |
36 | | - |
37 | | - public OffHeapMemory(long address, long size) { |
38 | | - if(address != 0L) { |
39 | | - this._data = address + HEADER_SIZE; |
40 | | - unsafe.putLong(address, size); |
41 | | - } |
42 | | - else { |
43 | | - this._data = 0L; |
44 | | - } |
45 | | - } |
46 | | - |
47 | | - public long headerAddress() { |
48 | | - return _data - HEADER_SIZE; |
49 | | - } |
50 | | - public long size() { |
51 | | - return (_data == 0) ? 0L : unsafe.getLong(headerAddress()) + HEADER_SIZE; |
52 | | - } |
53 | | - |
54 | | - public long address() { |
55 | | - return _data; |
56 | | - } |
57 | | - |
58 | | - public long dataSize() { |
59 | | - return (_data == 0) ? 0L : unsafe.getLong(headerAddress()); |
60 | | - } |
61 | | - |
62 | | - public MemoryReference toRef(ReferenceQueue<Memory> queue) { |
63 | | - return new OffHeapMemoryReference(this, queue); |
64 | | - } |
65 | | - |
66 | | - public void release() { |
67 | | - if(_data != 0) |
68 | | - UnsafeUtil.unsafe.freeMemory(headerAddress()); |
69 | | - } |
70 | | -} |
71 | | - |
72 | | -class OffHeapMemoryReference extends MemoryReference { |
73 | | - |
74 | | - /** |
75 | | - * Create a phantom reference |
76 | | - * @param m the allocated memory |
77 | | - * @param queue the reference queue to which GCed reference of the Memory will be inserted |
78 | | - */ |
79 | | - public OffHeapMemoryReference(Memory m, ReferenceQueue<Memory> queue) { |
80 | | - super(m, queue); |
81 | | - } |
82 | | - |
83 | | - public Memory toMemory() { |
84 | | - if(address != 0) |
85 | | - return new OffHeapMemory(address); |
86 | | - else |
87 | | - return new OffHeapMemory(); |
88 | | - } |
89 | | - |
90 | | - public String name() { return "off-heap"; } |
91 | | - |
92 | | -} |
93 | | - |
94 | 11 |
|
95 | 12 |
|
96 | 13 | /** |
97 | | - * Allocating off-heap memory |
| 14 | + * A default implementation of MemoryAllocator that allocates off-heap memory and releases allocated memories in a background thread. |
98 | 15 | * |
99 | 16 | * @author Taro L. Saito |
100 | 17 | */ |
101 | | -public class OffHeapMemoryAllocator implements MemoryAllocator { |
| 18 | +public class DefaultMemoryAllocator implements MemoryAllocator { |
| 19 | + |
| 20 | + private Logger logger = Logger.getLogger(DefaultMemoryAllocator.class); |
102 | 21 |
|
103 | | - private Logger logger = LoggerFactory.getLogger(OffHeapMemoryAllocator.class); |
104 | 22 |
|
105 | 23 | // Table from address -> MemoryReference |
106 | 24 | private Map<Long, MemoryReference> allocatedMemoryReferences = new ConcurrentHashMap<Long, MemoryReference>(); |
107 | 25 | private ReferenceQueue<Memory> queue = new ReferenceQueue<Memory>(); |
108 | 26 |
|
109 | 27 | { |
| 28 | + // Enable ANSI Color |
| 29 | + logger.enableColor(true); |
| 30 | + |
110 | 31 | // Start OffHeapMemory collector that releases the allocated memory when the corresponding Memory object is collected by GC. |
111 | 32 | Thread collector = new Thread(new Runnable() { |
112 | 33 | @Override |
@@ -136,15 +57,19 @@ public void run() { |
136 | 57 | */ |
137 | 58 | public long allocatedSize() { return totalAllocatedSize.get(); } |
138 | 59 |
|
| 60 | + /** |
| 61 | + * Allocate a memory of the specified byte length. The allocated memory must be released via `release` |
| 62 | + * as in malloc() in C/C++. |
| 63 | + * @param size byte length of the memory |
| 64 | + * @return allocated memory information |
| 65 | + */ |
139 | 66 | public Memory allocate(long size) { |
140 | 67 | if(size == 0L) |
141 | | - return new OffHeapMemory(); |
| 68 | + return new OffHeapMemory(); |
142 | 69 |
|
143 | 70 | // Allocate memory of the given size + HEADER space |
144 | 71 | long memorySize = size + OffHeapMemory.HEADER_SIZE; |
145 | | - long address = unsafe.allocateMemory(memorySize); |
146 | | - if(logger.isTraceEnabled()) |
147 | | - logger.trace(String.format("Allocated memory address:%x, size:%,d", address, size)); |
| 72 | + long address = UnsafeUtil.unsafe.allocateMemory(memorySize); |
148 | 73 | Memory m = new OffHeapMemory(address, size); |
149 | 74 | register(m); |
150 | 75 | return m; |
@@ -183,10 +108,9 @@ public void release(Memory m) { |
183 | 108 | synchronized(this) { |
184 | 109 | long address = m.headerAddress(); |
185 | 110 | if(allocatedMemoryReferences.containsKey(address)) { |
186 | | - long size = m.size(); |
187 | 111 | if(logger.isTraceEnabled()) |
188 | | - logger.trace(String.format("Released memory address:%x, size:%,d", address, size)); |
189 | | - totalAllocatedSize.getAndAdd(-size); |
| 112 | + logger.trace(String.format("Released memory address:%x, size:%,d", address, m.dataSize())); |
| 113 | + totalAllocatedSize.getAndAdd(-m.size()); |
190 | 114 | allocatedMemoryReferences.remove(address); |
191 | 115 | m.release(); |
192 | 116 | } |
|
0 commit comments