8

Googlers if you've got a heap dump with a root of coldfusion.runtime.CFDummyComponent read on.

Update 2/22/2011

Marc Esher of MXUnit fame found the exact same bug in a different context. His solution involves a large loop over a query solved by going from query="name" to from="1" to="#name.recordcount#" index="row". Another approach that works is using <cfthread> inside the loop as such:

<cfloop ...>
    <cfset threadName = "thread" & createUuid()>
    <cfthread name="#threadName#">
        <!--- do stuff --->
    </cfthread>
    <cfthread action="join" name="#threadName#">
</cfloop>

This is very effective when you run into situations where you need to do things inside the loop like queries and <cfmodule> inside <cffunction> so that the memory consumed is only for that iteration.

Old Question

Hoping someone else can confirm or tell me what I'm doing wrong. I am able to consistently reproduce an OOM running by calling the file oom.cfm (shown below). Using jconsole I am able to see the request consumes memory and never releases it until complete. The issue appears to be calling <cfmodule> inside of <cffunction>, where if I comment out the <cfmodule> call things are garbage collected while the request is running.

ColdFusion version: 9,0,1,274733

JVM Arguments

java.home=C:/Program Files/Java/jdk1.6.0_18
java.args=-server  -Xms768m -Xmx768m -Dsun.io.useCanonCaches=false -XX:MaxPermSize=512m -XX:+UseParallelGC -Xbatch -Dcoldfusion.rootDir={application.home}/ -Djava.security.policy={application.home}/servers/41ep8/cfusion.ear/cfusion.war/WEB-INF/cfusion/lib/coldfusion.policy -Djava.security.auth.policy={application.home}/servers/41ep8/cfusion.ear/cfusion.war/WEB-INF/cfusion/lib/neo_jaas.policy -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=56033

Test Case

oom.cfm (this calls template.cfm below - Adobe Bug #85736)

<cffunction name="fun" output="false" access="public" returntype="any" hint="">
    <cfset var local = structNew()/>
    <!--- comment out cfmodule and no OOM --->
    <cfmodule template="template.cfm">
</cffunction>

<cfset size = 1000 * 200>
<cfloop from="1" to="#size#" index="idx">
    <cfset fun()>
    <cfif NOT idx mod 1000>
        <cflog file="se-err" text="#idx# of #size#">
    </cfif>
</cfloop>

template.cfm

<!--- I am empty! --->

Update #2 (cfthread case from Elliott Sprehn - Adobe ColdFusion Bug #83359)

<cfthread name="test">  
  <cfloop from="1" to="10000" index="i">      
    <cflog text="This is very bad.">      
    <cflock name="test" timeout="10">      
    </cflock>  
  </cfloop>  
  <!--- Sleep a very long time (10 minutes) --->  
  <cfset sleep(600000)>
</cfthread>
Community
  • 1
  • 1
orangepips
  • 9,891
  • 6
  • 33
  • 57
  • I have run into occasions where multi-threading was killing my memory, and posted a few here on SO. Wouldn't surprise me if this was similar. – Ciaran Archer Jan 07 '11 at 17:43
  • 1
    What happens if you just do the cfmodule call inside the loop, omitting the function entirely? – Adam Tuttle Jan 07 '11 at 18:12
  • @Adam Tuttle: good comment, hadn't tested that way. When I tried garbage collection occurs during the request, so still points at `` inside ``. – orangepips Jan 07 '11 at 18:23
  • It sounds like a bug, then. File a bug report: http://cfbugs.adobe.com/cfbugreport/flexbugui/cfbugtracker/main.html – Adam Tuttle Jan 07 '11 at 18:52
  • @Adam Tuttle: am planning to log with Adobe, wanted to see first if anyone else can validate and/or refute. Now my other 2 cents, the Adobe bug tracker is the most awful thing in existence, they couldn't have made it worse if they'd tried. Unusable Flash interface, not searchable (tank God Elliott Sprehn mirrors it), bugs are opened and closed therein without explanation or identification of what release something will show up in. So that's why I posted here first. – orangepips Jan 07 '11 at 19:00
  • 1
    OK bug logged: http://cfbugs.adobe.com/cfbugreport/flexbugui/cfbugtracker/main.html#bugId=85736 - the tracker is still the worst thing in existence. – orangepips Jan 07 '11 at 19:16
  • @Orangepips: I agree that there are some problems with the flash interface; but it is much better than the black-hole that used to be bug reporting/feature requesting (which basically sent an email and then there was no response at all). And I hear that Adobe is trying to get the CF bugs moved over to the bug db they use for other products, which should be better. Baby steps. :) – Adam Tuttle Jan 07 '11 at 19:52
  • @Adam Tuttle: here's hoping... – orangepips Jan 07 '11 at 19:58
  • What happens if you put something in the file? – Mark Kruger Jan 08 '11 at 22:46
  • Putting something inside `template.cfm` doesn't change the result. The test case is the reduction of a much bigger piece of code where there *is* stuff inside the module. – orangepips Jan 08 '11 at 22:46

3 Answers3

5

I've not run into this before, but here's what I think is going on:

Each time cfmodule is called, a new memory space is created for it (which, IIRC, is the main difference between it and cfinclude). Because you are calling the cfmodule within the function, the cfmodule memory space technically belongs to that function's memory space. The function's memory is protected from garbage collection until the function is done. Result: heap fills, and you get an OOM error.

I don't think calling this a memory leak is correct, as it is behaving correctly, and when the function completes, the garbage collector can clear the hold on that memory. However, I can see how it might be inconvenient.

Ben Doom
  • 7,865
  • 1
  • 27
  • 30
  • 1
    +1 because this is my suspicion too. However it's a bug. Without the module call the function's memory allocation *is* garbage collected during the request. So adding a cfmodule call inside of it should make it part of that function's allocated memory and available for garbage collection as the function goes out of scope (e.g. the loop iterates), but this clearly does not happen. Seriously try the test case for yourself, with and without the modue inside the function, and you'll see. – orangepips Jan 07 '11 at 19:18
  • The cfmodule's memory space isn't attached to a named variable, it doesn't go out of scope until the function call ends. Bad design or bug? Personally, I think it's just bad design, but could be wrong. – Ben Doom Jan 07 '11 at 19:47
  • Marking this as the answer, but am still bitter overall (not at the answerer mind you). – orangepips Jan 07 '11 at 19:54
3

This problem manifests with lots of tags unfortunately. I've seen this with cflock inside cfthread. Write a very long running loop in a cfthread that uses cflock, you'll run out of memory eventually. It takes a long time, but it happens. I bet the retention problem exists in regular requests too, but you don't usually have a loop that runs hundreds of thousands of times with a cflock inside so no one notices.

I reported this bug a long time ago, but it never got fixed: http://www.elliottsprehn.com/cfbugs/bugs/83359

The best solution for now is to not use cfmodule inside a loop like this. Custom tags really weren't intended for calling 20k times in a single request. You're going to want to use UDFs instead. cfmodule is extremely expensive anyway and using a UDF will be noticeably faster.

  • Sphrehn: +1 I've added your example to the original question. Agreed that the notion of making the call so many times is bad, but it's also the matter of working with a codebase that's 8 or 9 years old, where there is a lot of code written that expects to be called using cfmodule/as a custom tag. – orangepips Jan 08 '11 at 15:43
0

Here is a discussion of a possibly related Coldfusion version 9 cfc memory leak problem: http://forums.adobe.com/thread/1034324?start=0&tstart=0

See this bug report on it: https://bugbase.adobe.com/index.cfm?event=bug&id=3124148

I don't believe Adobe released a fix for verion 9.01 but supposedly this problem is fixed in version 10. There are workarounds for most people (depending on the scope of their problem) for this not unlike what's been described here.

Gary
  • 1