Add a BBuf allocator for direct memory, that is also managed by a Cleaner
Motivation: Client code sometimes struggle with managing their buffer reference counts correctly, so there's a use case for buffers that are deallocated by cleaners. Modification: Add another allocator, directWithCleaner, which registers all the native memory segments with cleaners. Result: It's possible to get unpooled direct buffers, that are automatically deallocated by a cleaner if they are no longer strongly referenced. The same is not necessary for heap buffers, since they can be garbage collected like normal objects.
This commit is contained in:
parent
1aa439991a
commit
1f4e33b42a
@ -74,6 +74,18 @@ public interface Allocator extends AutoCloseable {
|
||||
};
|
||||
}
|
||||
|
||||
static Allocator directWithCleaner() {
|
||||
return new Allocator() {
|
||||
@Override
|
||||
public Buf allocate(long size) {
|
||||
checkSize(size);
|
||||
var segment = allocateNative(size);
|
||||
segment.registerCleaner(Statics.CLEANER);
|
||||
return new BBuf(segment, SEGMENT_CLOSE);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static Allocator pooledHeap() {
|
||||
return new SizeClassedMemoryPool() {
|
||||
@Override
|
||||
|
@ -0,0 +1,33 @@
|
||||
package io.netty.buffer.b2;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class DirectBBufWithCleanerTest extends DirectBBufTest {
|
||||
@Override
|
||||
protected Allocator createAllocator() {
|
||||
return Allocator.directWithCleaner();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bufferMustBeClosedByCleaner() throws InterruptedException {
|
||||
var allocator = createAllocator();
|
||||
allocator.close();
|
||||
int iterations = 100;
|
||||
int allocationSize = 1024;
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
allocateAndForget(allocator, allocationSize);
|
||||
System.gc();
|
||||
System.runFinalization();
|
||||
}
|
||||
var sum = Statics.MEM_USAGE_NATIVE.sum();
|
||||
var totalAllocated = (long) allocationSize * iterations;
|
||||
assertThat(sum, lessThan(totalAllocated));
|
||||
}
|
||||
|
||||
protected void allocateAndForget(Allocator allocator, long size) {
|
||||
allocator.allocate(size);
|
||||
}
|
||||
}
|
@ -20,28 +20,12 @@ import org.junit.Test;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class PooledDirectBBufWithCleanerTest extends DirectBBufTest {
|
||||
public class PooledDirectBBufWithCleanerTest extends DirectBBufWithCleanerTest {
|
||||
@Override
|
||||
protected Allocator createAllocator() {
|
||||
return Allocator.pooledDirectWithCleaner();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bufferMustBeClosedByCleaner() throws InterruptedException {
|
||||
var allocator = createAllocator();
|
||||
allocator.close();
|
||||
int iterations = 100;
|
||||
int allocationSize = 1024;
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
allocateAndForget(allocator, allocationSize);
|
||||
System.gc();
|
||||
System.runFinalization();
|
||||
}
|
||||
var sum = Statics.MEM_USAGE_NATIVE.sum();
|
||||
var totalAllocated = (long) allocationSize * iterations;
|
||||
assertThat(sum, lessThan(totalAllocated));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buffersMustBeReusedByPoolingAllocatorEvenWhenDroppedByCleanerInsteadOfExplicitly()
|
||||
throws InterruptedException {
|
||||
@ -58,8 +42,4 @@ public class PooledDirectBBufWithCleanerTest extends DirectBBufTest {
|
||||
assertThat(sum, lessThan(totalAllocated));
|
||||
}
|
||||
}
|
||||
|
||||
protected void allocateAndForget(Allocator allocator, long size) {
|
||||
allocator.allocate(size);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user