Quick & Dirty ColdFusion JVM Memory Monitor
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.
<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>

Comments
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
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?