Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

extension for tracking off-heap memory use for netty #475

Closed
brharrington opened this issue Oct 3, 2017 · 5 comments
Closed

extension for tracking off-heap memory use for netty #475

brharrington opened this issue Oct 3, 2017 · 5 comments
Milestone

Comments

@brharrington
Copy link
Contributor

Netty is used widely at Netflix and it uses off-heap memory that is not showing up in the existing buffer pool metrics. It would be useful if we could support an extension for tracking the memory use of netty allocators.

@brharrington brharrington added this to the 0.59.0 milestone Oct 3, 2017
@brharrington
Copy link
Contributor Author

@brharrington
Copy link
Contributor Author

Test program:

import java.lang.management.*;
import java.lang.reflect.*;
import java.nio.*;
import sun.misc.*;

public class Test {

  private static void dumpBufferStats() {
    System.out.println("==========================================");
    System.out.println("BufferPoolMXBean");
    System.out.println("------------------------------------------");
    for (BufferPoolMXBean mbean : ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class)) {
      System.out.printf("%s: count %d, capacity %d, used %d%n",
        mbean.getName(),
        mbean.getCount(),
        mbean.getTotalCapacity(),
        mbean.getMemoryUsed());
    }

    JavaNioAccess.BufferPool pool = SharedSecrets.getJavaNioAccess().getDirectBufferPool();
    System.out.printf("SharedSecrets: %s: count %d, capacity %d, used %d%n",
      pool.getName(),
      pool.getCount(),
      pool.getTotalCapacity(),
      pool.getMemoryUsed());
    System.out.printf("VM.maxDirectMemory: %d%n", VM.maxDirectMemory());
    System.out.println("==========================================\n\n");
  }

  private static Unsafe getUnsafe() throws Exception {
    Field f = Unsafe.class.getDeclaredField("theUnsafe");
    f.setAccessible(true);
    return (Unsafe) f.get(null);
  }

  public static void main(String[] args) throws Exception {
    dumpBufferStats();

    System.out.println("ByteBuffer.allocateDirect(4096)");
    ByteBuffer.allocateDirect(4096);

    dumpBufferStats();

    System.out.println("Unsafe.allocateMemory(4096)");
    long address = getUnsafe().allocateMemory(4096);

    dumpBufferStats();

    System.out.println("Unsafe.freeMemory(address)");
    getUnsafe().freeMemory(address);

    dumpBufferStats();
  }
}

Neither BufferPoolMXBean or SharedSecrets captures memory allocated using Unsafe.allocateDirect. Output:

$ java Test
==========================================
BufferPoolMXBean
------------------------------------------
direct: count 0, capacity 0, used 0
mapped: count 0, capacity 0, used 0
SharedSecrets: direct: count 0, capacity 0, used 0
VM.maxDirectMemory: 3817865216
==========================================


ByteBuffer.allocateDirect(4096)
==========================================
BufferPoolMXBean
------------------------------------------
direct: count 1, capacity 4096, used 4096
mapped: count 0, capacity 0, used 0
SharedSecrets: direct: count 1, capacity 4096, used 4096
VM.maxDirectMemory: 3817865216
==========================================


Unsafe.allocateMemory(4096)
==========================================
BufferPoolMXBean
------------------------------------------
direct: count 1, capacity 4096, used 4096
mapped: count 0, capacity 0, used 0
SharedSecrets: direct: count 1, capacity 4096, used 4096
VM.maxDirectMemory: 3817865216
==========================================


Unsafe.freeMemory(address)
==========================================
BufferPoolMXBean
------------------------------------------
direct: count 1, capacity 4096, used 4096
mapped: count 0, capacity 0, used 0
SharedSecrets: direct: count 1, capacity 4096, used 4096
VM.maxDirectMemory: 3817865216
==========================================



$ java -XX:MaxDirectMemorySize=4g Test
==========================================
BufferPoolMXBean
------------------------------------------
direct: count 0, capacity 0, used 0
mapped: count 0, capacity 0, used 0
SharedSecrets: direct: count 0, capacity 0, used 0
VM.maxDirectMemory: 4294967296
==========================================


ByteBuffer.allocateDirect(4096)
==========================================
BufferPoolMXBean
------------------------------------------
direct: count 1, capacity 4096, used 4096
mapped: count 0, capacity 0, used 0
SharedSecrets: direct: count 1, capacity 4096, used 4096
VM.maxDirectMemory: 4294967296
==========================================


Unsafe.allocateMemory(4096)
==========================================
BufferPoolMXBean
------------------------------------------
direct: count 1, capacity 4096, used 4096
mapped: count 0, capacity 0, used 0
SharedSecrets: direct: count 1, capacity 4096, used 4096
VM.maxDirectMemory: 4294967296
==========================================


Unsafe.freeMemory(address)
==========================================
BufferPoolMXBean
------------------------------------------
direct: count 1, capacity 4096, used 4096
mapped: count 0, capacity 0, used 0
SharedSecrets: direct: count 1, capacity 4096, used 4096
VM.maxDirectMemory: 4294967296
==========================================

@brharrington brharrington modified the milestones: 0.59.0, 0.60.0 Nov 8, 2017
@brharrington brharrington modified the milestones: 0.60.0, 0.61.0 Nov 22, 2017
@brharrington brharrington modified the milestones: 0.61.0, 0.62.0 Jan 17, 2018
@brharrington brharrington modified the milestones: 0.62.0, 0.63.0 Jan 31, 2018
@brharrington brharrington modified the milestones: 0.63.0, 0.64.0 Mar 12, 2018
@brharrington brharrington modified the milestones: 0.64.0, 0.65.0 Apr 16, 2018
@brharrington brharrington modified the milestones: 0.65.0, backlog Apr 27, 2018
@asgs
Copy link

asgs commented Oct 2, 2018

@brharrington in both the tests you've done above, the used and capacity values were 0 in the beginning and then after calling ByteBuffer.allocateDirect(4096), they were set to 4096 accordingly. But they remained the same even after calling Unsafe.allocateMemory(4096). So, did you mean to say Unsafe.allocateMemory instead?

Neither BufferPoolMXBean or SharedSecrets captures memory allocated using Unsafe.allocateDirect. Output:

Also, is the BufferPoolMeter's equivalent of BufferPoolMXBean's usedMemory the one in this line?

return registry.createId("jvm.buffer.memoryUsed").withTag("id", id);

@brharrington
Copy link
Contributor Author

Yes, I meant Unsafe.allocateMemory.

The buffer pool memoryUsed metric will get set to the value from BufferPoolMXBean.getMemoryUsed.

@brharrington
Copy link
Contributor Author

For a lot of the common netty usage, it is probably possible to use PooledByteBufAllocator.metric. The other problem we have run into is a lot of our internal usage now shadows netty (e.g. gRPC) so it is a bit harder for us to hook into the right places for each shadowed version. That is partly why I would prefer to capture it at the JVM level, but I don't think that is possible right now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants