Skip to content

ColdFusion Memory Leaks: Part I – profiler introduction

by Mike on October 12, 2006

Over the last year or so I’ve been dealing with memory leaks in ColdFusion.  Some have been code related, but others seem to be issues with the way ColdFusion handles garbage collection of CFCs.  Recently, we’ve made some breakthroughs at my company, so I thought I would share the steps that we took to identify memory leaks along with some interesting behaviors that we observed. 

Hopefully, when I am finished, you will be on your way to changing your memory profile to look something like this… (This is an actual application profile under load)

 
Before
 
After

In this post, I will show you the steps that I used to setup an environment that enabled me to identify the problem.

Step 1:  configure your jvm: 5.0 is the way to go

    The first thing that I tried was to use a profiling tool (i.e. jprobe or yourkit) against my existing coldfusion/jrun instance.  This proved to be a mistake because the profiler added so much overhead to the jvm that the application became unresponsive.  The solution was to use a Java 5 jvm.  Jrun does not support Java 5 (JVM 1.5), but for the most part your application should run to the point that you can profile effectively.

Step 2:  running with BEA Jrockit


    For our example, I will suggest using the 1.5 jrockit jvm provided by BEA.  The reason for this is because they have some powerful profiling tools that I will talk about later.

First, go to the following URL, and install the Jrockit 5.0 JDK

http://commerce.bea.com/products/weblogicjrockit/jrockit_prod_fam.jsp

(For the rest of the example I will assume that you installed the JDK at C:\Program_Files\Java\jrockit-R26.4.0-jdk1.5.0_06\ )


you will also need to download a Jrockit Mission Control 1.0 license key. (you may need to register for that), save this file named as license.bea and move it to the following folder.
\jrockit-R26.4.0-jdk1.5.0_06\jre\

After that, modify your jvm.config file and change java.home to the following… (make sure to use forward slashes)

java.home=C:/Program Files/Java/jrockit-R26.4.0-jdk1.5.0_06/jre

to enable profiling, you will need to add the following to your jvm args… (specify any port that you want)

-Xmanagement -Djrockit.managementserver.port=9010

Now restart the CF service and you are ready to go.

Step 3:  memory leak detector
   
    Now for the fun part… the Jrockit JDK ships with a tool called "Memory Leak Detector", To start using this, browse to the following folder…

C:\Program Files\Java\jrockit-R26.4.0-jdk1.5.0_06\memleak

Then double click on MemoryLeakDetector.jar (you may have to run it from the command line if that doesn’t work).  The tool should start, and you should be able to specify the server and port (that you specified in jvm.config). 

The next step is critical to effectively profile a ColdFusion application.  From what I’ve observed, Internally, most of your variable data will be stored within objects of type coldfusion.runtime.variable.  CFC classes don’t hold much data, so they take up a very small percentage of the jvm heap.  We need to change the memory leak detector settings to look at small heap sizes.  To do this, browse to File/Preferences/Trend and change "lowest heap usage to report" to 0.

Step 4:  example

To show you how to use the memory leak detector, we will create an example, for this example I will create a cfc, this cfc has 2 methods, init() that returns itself, and doSomething() which will load 100 instances of itself into the variables scope of the object.



	

	
		
	

	
		

		
			
		
	

Next, create a simple cfm page that will load the cfc into memory and call the doSomething() function.  Calling this .cfm page should create 101 instances of test in the application scope (1 loaded into application, and 100 loaded within itself)






After you have executed the page, return to your memory leak detector and filter by "cf" (you can also filter by "cold" to see internal ColdFusion representations).  You should now see something like this in the memory leak detector.

you will now see that we have created 101 instances of test.cfc in the memory heap (along with a reference to test.cfm that it is keeping alive, plus the empty classes it uses internally to identify the init() and doSomething() methods.

Congratulations!

If you have made it to this point, you are on your way to profiling your application.  If you leave the memory leak detector running under load, it will eventually track the growth of objects, and can be used to pinpoint potential problems. In my next post I will identify some of the potential problem behaviors of the ColdFusion engine, and how it can potentially "leak" object references in simple examples.

Credits and Reading materials
The basis of this strategy is outlined in greater detail in a pdf book created by Grant Straker.  He focuses on other aspects of optimizing cf performance besides memory usage as well.  If you are headed to Max, then I would highly recommend checking out his talk.

His pdf book is available at…

http://www.cfperformance.com/

In my opinion this could be the most valuable $50 that you will ever spend on CF knowledge, and is well worth the money.

From → ColdFusion, Memory

16 Comments
  1. Sami Hoda permalink

    Very impressive Mike. Keep up the good work!

  2. John Farrar permalink

    I was under the impression that the variables scope in a CFC is the persistance scope. If you want a private persistant variable to the CFC that is visible by all the functions you use variable. It is hid from the outside world, but visible to the CFC.

    Does this occur only in persistant CFCs or does it also occur in CFCs that are suppose to be cleared out at end of request?

  3. John-
    I’m guessing this comment applies to the variables scope example… You are correct, variables scope within a cfc should live for the life of the cfc, and is global to all functions within the cfc. The scenario that I discovered seems to occur when you are calling a function in a cfc that is persistant. In a simple example, cfcs created during a request should be cleaned up by the GC. However, I’m going to post an example soon that may show that this isn’t always the case.

  4. spiraldev permalink

    I am not very familiar with JVM. So go easy the part of you instructions that I am having a problem with is the java.home=C:/Program Files/Java/jrockit-R26.4.0-jdk1.5.0_06/jre I am not sure where I need to make this modification. Any advice will be appreciated.

  5. you will need to make the change in your jvm.config file by default this would be located at

    C:\CFusionMX7\runtime\bin\

    I would highly recommend making a copy of your jvm.config file before you make any modifications. (rename it something like jvm.config.old)

  6. Hemant permalink

    There is a hotfix now available for this issue. Please see

    http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=kb401239

    This should fix the problem.

    Thanks,
    Hemant

  7. This looks like an excellent tool. I am having trouble setting up Jrocket though. The CF server will not restart once I change the JVM to use Jrocket. I have played around with some JVM settings but no luck. Does anyone have any suggestions?

  8. @JT

    You might want to try adding the jrockit bin folder to your windows path environment variable. I had this issue on a few machines and that was the solution. You can get there by going to windows system properties/Advanced/Environment Variables. Edit the Path System variable and add the path to your jrockit bin folder, something like;
    C:\Java\jrockit-R26.4.0-jdk1.5.0_06\jre\bin

    Hope that works,
    Mike

  9. Abram permalink

    I was having problems with starting CF (cfmx7/linux) after changing the jvm. I got it to work by adding the argument: authenticate=false to the -Xmanagement option:

    -Xmanagement:authenticate=false -Djrockit.managementserver.port=9010

    (great post by the way Mike)

    HTH

  10. Greg permalink

    I just downloaded JRockit jrockit-R27.4.0-jdk1.5.0_1, is there any way i can get some help setting up the memleak correctly?

    I am using the authenticate:false and passed one error, but it seems like the path to the memleak tool is different then in this blog. I am getting
    Could not open Memory Leak Detector for SWI-CORE-WEB01:9010.
    java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is:
    javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is: (trimed)

    Also, if I start JRun Admin, it grabs the port and then will not allow Cfusion instance to start.

  11. Brett S permalink

    Hey Greg – Add this option to your java args:

    -Djrockit.managementserver.ssl=false

    see: http://e-docs.bea.com/jrockit/tools/intro/mc_comm.html#wp999032

    Thanks for this great post!

  12. Yes, I think you should assume that this could have overhead, I wouldn’t recommend enabling in a production environment.

  13. Does adding this to the instance’s jvm affect the performance of the instance at all?

  14. the line:
    <cfset arrayAppend(variables.holderArray) = createObject("component","test").init() />

    should read:
    <cfset arrayAppend(variables.holderArray, createObject("component","test").init() ) />

  15. Just letting you know, all the images appear to be broken in this post.

  16. mike permalink

    Thanks Brad, think I have all the images fixed now that the site has moved.

Comments are closed.