Search code examples
nettydirectmemory

Netty PooledDirect ByteBuf and ArrayList unexpected behaviour


This seems to be a silly mistake as I couldn't find why all the entries were not removed. I am running with JAVA_OPTS:

-XX:MaxDirectMemorySize=67108864 -Dio.netty.leakDetectionLevel=advanced -D-Dio.netty.allocator.type=pooled -XX:+UseG1GC -Xms40m -Xmx40m -Dio.netty.allocator.numDirectArenas=4

Here is the complete code:

private ByteBufAllocator alloc = PooledByteBufAllocator.DEFAULT;

//Configure the arena
//java -Dio.netty.allocator.numDirectArenas=... -Dio.netty.allocator.numHeapArenas=... 
public ByteBuf createObject(int size){
    return alloc.directBuffer(size);
}

public static void main(String[] args) throws InterruptedException {
    ArrayList<ByteBuf> arr = new ArrayList<>();
    try {
        DiameterLoggingConfiguration.initLogger();

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    ByufferTest bt = new ByufferTest();
    //Total of 66060288 ~ slightly less than 64 mb of direct memory
    for(int i=0;i<64512;i++){
        //Each instance of 1024 bytes
        arr.add(bt.createObject(1024));

    }

    BufferedReader br = new BufferedReader(new
              InputStreamReader(System.in));
    try {
        br.readLine();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("Now releasing.."+arr.size());

    for(int i=0;i<arr.size();i++){
        ByteBuf b = arr.remove(i);
        b.release();
    }

    System.out.println("Now array size ="+arr.size());

    Thread.sleep(100000);

}

Output is :

Now releasing..64512 After array size =32256

No idea only exactly half of the entries were removed. Still there are ByteBuf entries in the ArrayList.


Solution

  • Thats because you use:

     for(int i=0;i<arr.size();i++){
        ByteBuf b = arr.remove(i);
        b.release();
    }
    

    This will no work as you increment the index by 0 but also remove a buffer. This way you will skip buffers.

    Better use an Queue and just use poll();

     Queue<ByteBuf> arr = new ArrayDeque<>();
     for(;;){
        ByteBuf b = arr.poll();
        if (b == null) {
            break;
        }
        b.release();
    }