Quick & Dirty ColdFusion JVM Memory Monitor

Posted by Dan on Dec 13, 2007 @ 9:27 AM

Yesterday, I posted on how to use JConsole to monitor ColdFusion's JVM. Today I wanted to give you a quirk and dirty script you can run on ColdFusion 8 which will give you a lot of the same memory information—but wrapped up into a CF script. The script is based on some code from Steve Brownlee's useful post on accessing ColdFusion internals using Java.

The key benefit to this method is there's nothing to install—just copy the code on a server and run it. Obviously, this only works if the server is responding and is not going to be as thorough as using JConsole. I have found this script handy to just give you a quick overview of the system state.

I've only tested the code in CF8, but it doesn't utilize any special ColdFusion classes—it utilizes the core Java classes. This code should work on any ColdFusion installation using Java 5 (v1.5) or higher.

<html>
<head>
    <title>
        JVM Monitor -
        <cfoutput>
            #server.coldfusion.ProductName#
            - #server.coldfusion.ProductLevel#
            v#server.coldfusion.ProductVersion#
        </cfoutput>
    </title>
</head>
<body>
<script type="text/javascript">document.write("<h1>" + document.title + "</h1>");</script>
<cfscript>
/**
* Pass in a value in bytes, and this function converts it to a human-readable format of bytes, KB, MB, or GB.
* Updated from Nat Papovich's version.
* 01/2002 - Optional Units added by Sierra Bufe (sierra@brighterfusion.com)
*
* @param size     Size to convert.
* @param unit     Unit to return results in. Valid options are bytes,KB,MB,GB.
* @return Returns a string.
* @author Paul Mone (sierra@brighterfusion.compaul@ninthlink.com)
* @version 2.1, January 7, 2002
*/

function byteConvert(num) {
    var result = 0;
    var unit = "";
    // Set unit variables for convenience
    var bytes = 1;
    var kb = 1024;
    var mb = 1048576;
    var gb = 1073741824;
    // Check for non-numeric or negative num argument
    if (not isNumeric(num) OR num LT 0)
        return "Invalid size argument";
    // Check to see if unit was passed in, and if it is valid
    if ((ArrayLen(Arguments) GT 1)
        AND ("bytes,KB,MB,GB" contains Arguments[2]))
    {
        unit = Arguments[2];
    // If not, set unit depending on the size of num
    } else {
         if     (num lt kb) {    unit ="bytes";
        } else if (num lt mb) {    unit ="KB";
        } else if (num lt gb) {    unit ="MB";
        } else                {    unit ="GB";
        }
    }
    // Find the result by dividing num by the number represented by the unit
    result = num / Evaluate(unit);
    // Format the result
    if (result lt 10)
    {
        result = NumberFormat(Round(result * 100) / 100,"0.00");
    } else if (result lt 100) {
        result = NumberFormat(Round(result * 10) / 10,"90.0");
    } else {
        result = Round(result);
    }
    // Concatenate result and unit together for the return value
    return (result & " " & unit);
}
function formatMB(num){
    return byteConvert(num, "MB");
}
// Create Java object instances needed for creating memory charts
runtime = createobject("java", "java.lang.Runtime");
mgmtFactory = createobject("java", "java.lang.management.ManagementFactory");
pools = mgmtFactory.getMemoryPoolMXBeans();
heap = mgmtFactory.getMemoryMXBean();
jvm = structNew();
jvm["JVM - Used Memory"] = formatMB(runtime.getRuntime().maxMemory()-runtime.getRuntime().freeMemory());
jvm["JVM - Max Memory"] = formatMB(runtime.getRuntime().maxMemory());
jvm["JVM - Free Memory"] = formatMB(runtime.getRuntime().freeMemory());
jvm["JVM - Total Memory"] = formatMB(runtime.getRuntime().totalMemory());
jvm["Heap Memory Usage - Max"] = formatMB(heap.getHeapMemoryUsage().getMax());
jvm["Heap Memory Usage - Used"] = formatMB(heap.getHeapMemoryUsage().getUsed());
jvm["Heap Memory Usage - Committed"] = formatMB(heap.getHeapMemoryUsage().getCommitted());
jvm["Heap Memory Usage - Initial"] = formatMB(heap.getHeapMemoryUsage().getInit());
jvm["Non-Heap Memory Usage - Max"] = formatMB(heap.getNonHeapMemoryUsage().getMax());
jvm["Non-Heap Memory Usage - Used"] = formatMB(heap.getNonHeapMemoryUsage().getUsed());
jvm["Non-Heap Memory Usage - Committed"] = formatMB(heap.getNonHeapMemoryUsage().getCommitted());
jvm["Non-Heap Memory Usage - Initial"] = formatMB(heap.getNonHeapMemoryUsage().getInit());
for( i=1; i lte arrayLen(pools); i=i+1 ) jvm["Memory Pool - #pools[i].getName()# - Used"] = formatMB(pools[i].getUsage().getUsed());
</cfscript>
<cfdump var="#jvm#" label="JVM Memory Monitor" />
</body>
</html>

Categories: HTML/ColdFusion, Java

9 Comments

  • Nice Work...should come in handy. For all of the benefits of Java-based CF (and there are MANY), all of this memory tuning hassle kind of makes my pine for the pre-Java days. You could throw some NASTY code at CF 4.5/5 and it would just keep humming along.
  • Hi Dan,
    Hope you can help. I ran the memory script you wrote to monitor JVM memory (very nice!) and it says
      Heap Memory Usage - Max: 63.6 MB,
      Heap Memory Usage - Initial: 0.00 MB

    yet I have set the JVM Heapsize to 1024MB (-Xms1024m -Xmx1024m )
    Why is my Heap size not reaching 1024Mb

    Our Server (CF8) keeps crashing (java.lang.OutOfMemoryError) and i'm trying to debug it.
    Any help much appreciated.
    Thanks,
    Mathew
  • @Mathew:

    The "Heap Memory Usage - Initial" should definitely read 1024 (or close to it.) Are you sure the JVM settings you set are actually being used? Also, did you actually restart the CF services after making the changes?

    What's does your full "java.args" line look like in your jvm.config file?

    It's possible you have contradictory settings.

    Also, what version of CF are you using?
  • This is great nice and simple!!!
  • Your tool is great. I have began using it on all of my sites. I have a weird issue that continues to show its face. I get random 500 errors. I have read tons of posts with no clear answer. I am currently using your tool to determine if I have a GC/heap problem. Any thoughts?
  • I just checked and this code appears to be working correctly with ColdFusion 10 Developer v10.0.0.281485.
  • Dan,

    Very nice work! but I am getting the same issue "Heap Memory Usage - Initial: 0.00 MB" I have CF 9.0.1 on wndows 2003 box
  • Hey, Dan (and readers). I just had occasion to check out this post again, and I can report to readers that 10 years later, the code still works. :-) Tested on CF2016 with Java 8.

    It even reports on the Metaspace (which replaced the Permsize that had existed in Java 7 and earlier), because Dan smartly looped through available memory spaces rather than hard-coding their names.

    As for those having problems (like weird values for the max heap or initial size), there must be something specific to your setup. My values are reporting accurately.

    To be clear, though, it doesn't report a size EXACTLY equal to the XMX, but that's because the JVM doesn't report it that way. Rather, as as Dan said, it reports a number close to it (in my case, an xmx of 1024m on my dev laptop reported as 911m in the display), and as it does in other JVM tools. (And FWIW, my initial size is reporting a non-zero.)

    For those without a more complete monitoring solution (the CF Enterprise Server Monitor, FusionReactor, SeeFusion, or other JVM tools), it's helpful to see the memory usage via this tool of Dan's. (I will note that for those on CF10 and above, if you enable the new "metrics logging" feature of the CF Admin debugging output page, that log tracks several metrics every minute, including the heap used.)

    Dan's code could be evolved in some ways, of course (it's just as important to know the max for the other parts of JVM memory, like the codecache and the permsize/metaspace), but I won't look a gift horse in the mouth. And anyone could offer the code here to get those. Indeed, it probably warrants being a github project. I leave those as exercises for readers.

    I will note that for those wanting to know more about CF monitoring tools, I keep a list as a category of my CF411 site, specifically http://www.cf411.com/cfmon (and I have a link to this post as a "see also" there).

    Finally, if anyone ever struggles with troubleshooting memory or other CF problems, I will note that I also have a category there for CF troubleshooting consultants, http://cf411.com/cftrouble (which includes myself among others).
  • Charlie,

    Thanks for the valuable information!

Comments for this entry have been disabled.