Quick & Dirty ColdFusion JVM Memory Monitor

Categories: HTML/ColdFusion, Java

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>

Related Blog Entries

Comments

Troy Allen's Gravatar 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.
Mathew Sayers's Gravatar 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
Dan G. Switzer, II's Gravatar @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?

Add Comment



If you subscribe, any new posts to this thread will be sent to your email address.