Not sure if this is the best place for this… but here we are.
It has pained me for a long time that I cannot see how much direct memory my Java application is using. JME has BufferUtils which goes through some backflips to figure this out at least within the buffers that it allocated.
Scratching at the back of my brain has been the memory that the JDK jconsole app can see this information. It’s certainly available to the JVM. So I finally got motivated to look into it. Sure enough, jconsole not only has access to this but it’s accessing it using one of the MBeans built into the JVM.
The topic of MBeans is too long to go into here if you don’t already know what they are. Suffice it to say, that applications can instrument themselves and provide external control through JMX MBeans. And the JVM has been doing this for a long time. The best part, you can pretty easily access these if you know how.
I drudged up some of my old server management experience and did some deep-diving. The java.management package is really kind of cool if you ever want to take a look. These are the things the JVM provides to us “out of the box” with nice interfaces and stuff already built. Unfortunately, the direct BufferPool is not one of these things so requires direct MBean-style access. Still, I highly recommend looking at those other classes because you can get all kinds of really juicy info about the running JVM… GC performance in the different pools, CPU usages, thread stats, etc…
Anyway, the culmination of this quest for direct memory usage is a simple utility class:
[java]public class MemoryUtils {
private static MBeanServer mbeans = ManagementFactory.getPlatformMBeanServer();
private static ObjectName directPool;
static {
try {
// Create the name reference for the direct buffer pool’s MBean
directPool = new ObjectName(“java.nio:type=BufferPool,name=direct”);
} catch (MalformedObjectNameException ex) {
Logger.getLogger(MemoryUtils.class.getName()).log(Level.SEVERE, “Error creating direct pool ObjectName”, ex);
}
}
public static long getDirectMemoryUsage() {
try {
Long value = (Long)mbeans.getAttribute(directPool, "MemoryUsed");
return value == null ? -1 : value;
} catch (JMException ex) {
Logger.getLogger(MemoryUtils.class.getName()).log(Level.SEVERE, "Error retrieving 'MemoryUsed'", ex);
return -1;
}
}
public static long getDirectMemoryCount() {
try {
Long value = (Long)mbeans.getAttribute(directPool, "Count");
return value == null ? -1 : value;
} catch (JMException ex) {
Logger.getLogger(MemoryUtils.class.getName()).log(Level.SEVERE, "Error retrieving 'Count'", ex);
return -1;
}
}
public static long getDirectMemoryTotalCapacity() {
try {
Long value = (Long)mbeans.getAttribute(directPool, "TotalCapacity");
return value == null ? -1 : value;
} catch (JMException ex) {
Logger.getLogger(MemoryUtils.class.getName()).log(Level.SEVERE, "Error retrieving 'TotalCapacity'", ex);
return -1;
}
}
}
[/java]
The usage and counts are the most interesting ones. I provide access to TotalCapacity but this is not a value that makes any sense to me. It seems it is always just slightly less than usage… which a) makes no sense, and b) doesn’t seem useful. I was really hoping for a way to figure out what the max direct mem setting was but I have been unsuccessful.
Anyway, I can now easily add direct memory stats to my debug HUDs along with the other regular heap stats I always do:
(now I just have to figure out why my new Mythruna engine seems to use twice the direct mem of the old one…)