This piece of code:
<cfscript>
for (j = 1 ; j LTE 500000 ; j = (j + 1))
{
dummyc = createObject("component","Dummy");
dummyc.dummyf();
}
</cfscript>
that creates objects like this one:
<cfcomponent name="Dummy" output="false">
<cffunction name="dummyf" access="public" output="false" hint="" returnType="void">
</cffunction>
</cfcomponent>
A function needs to be executed on the cfc for it to start using memory, seems like its lazy-initialized.
Is using upto about 2 gigabytes of memory on CF9.
And almost nothing on CF8.
I analyzed a heap dump in eclipse memory analysis tool (MAT).
All the cfc's created in cf9 stay referenced under a java object and this
is why they are not garbage collected.
The cfc's in memory comprise of CFdummycomponent, variablescope and some other java objects. Because the references to them are kept, even though they are not referenced in coldfusion anymore, java cannot garbage collect them.
This basically means that batch processing can not be done with coldfusion anymore (using cfc's), unless a lot of memory is allocated.
On cf8 this was not a problem, because stuff not referenced in coldfusion was
not references in underlying java either anymore.
(cf8 did keep queries, cfsavecontent and some other stuff in memory, but i did not use this).
Can anybody confirm this or give me a solution?
I tried so much things, nothing helps, i tried almost all cf9 admin settings.
Im am creating a lot of cfc's in a batch process, this was no problem on cf8, but now we need 5,5g of memory for this batch process while in the past just needed 1g.
Thanks in advance,
Klaas-Jan Winkel
Actually, it has been reported as a bug:
https://bugbase.adobe.com/index.cfm?event=bug&id=3124148
But they say its fixed in coldfusion 10, but thats no fix for 9 ofcourse.
The fix reported in that bug, actually works!
| <cfset var j = -1> | ||
| <cfset var dummyc = ""> | ||
| <cfset var fusionContext = getPageContext().getFusionContext() > | ||
<cfset var dummyfield = fusionContext.getClass().getDeclaredField('dummyCompMap') /> <cfset dummyfield.setAccessible(true) /> |
| <Cfloop from="1" to="500000" index="j"> | |||||
| <cfset dummyc = createObject("component","Dummy")> | |||||
| <cfset dummyc.dummyf()> | |||||
| <cfset dummyfield.set(fusionContext, JavaCast('null', 0)) /> | |||||
| </cfloop> |
Make the code absolutely use no memory at all.
I also tested this in real code, where objects in the loop are not used anymore, but outside are still used.
The code still works, so the objects still used will not be gone with this fix.
It seems that the property dummycompmap can actually be completely set to null.
Im not sure what this property is actually used for, it seems like a garbage dump for all cfc's created.
I thought it might be for reusage of objects, to get better cfc performance. I did some tests:
Without fix: 4,2 seconds.
With fix: 3 seconds!
So definitely not performance related.
The increase in cfc creation speed might be due to the fact that no massive memory allocation has to occur.
So this is a completely valid workaround.
greets,
klaas
(sorry for the table, im lazy, no idea how that copy pasted there)
ATTENTION:
Can you guys please vote on the new bug i created:
https://bugbase.adobe.com/index.cfm?event=bug&id=3286878
Because the other one has status: fixed, and i think is not likely to be checked again by adobe.
(also added a heap dump and graphs as attachments to support the case)
Ive made a cfc for the fix:
<!-------------------------------------------------------------------- ---
Author : Klaas-Jan Winkel
Date : 7/13/2012
Description :
Forum: http://forums.adobe.com/message/4555371#4555371 / Bug: https://bugbase.adobe.com/index.cfm?event=bug&id=3286878
Todo:
Modification History:
---------------------------------------------------------------------- ->
<cfcomponent output="false">
<cfset ISCF9 = server.coldfusion.productname neq "BlueDragon" and server.coldfusion.productname neq "Railo" and left(SERVER.ColdFusion.ProductVersion,1) eq 9>
<!------------------------------------------- CONSTRUCTOR ------------------------------------------->
<cffunction name="init" access="public" returntype="any" output="false">
<!--- Any custom constructor code here --->
<cfif ISCF9>
<cfset instance.fusionContext = getPageContext().getFusionContext() >
<cfset instance.dummyfield = instance.fusionContext.getClass().getDeclaredField('dummyCompMap') />
<cfset instance.dummyfield.setAccessible(true) />
</cfif>
<cfreturn this>
</cffunction>
<!------------------------------------------- PUBLIC ------------------------------------------->
<cffunction name="clearMemory" access="public" output="false" hint="" returnType="void">
<cfif ISCF9>
<cfset instance.dummyfield.set(instance.fusionContext, JavaCast('null', 0)) />
</cfif>
</cffunction>
</cfcomponent>
North America
Europe, Middle East and Africa
Asia Pacific