2011-01-07 4 views
8

Googlers, wenn Sie einen Heap-Dump mit einer Wurzel von coldfusion.runtime.CFDummyComponent haben, lesen Sie weiter.Memory Leak Looping cfmodule innerhalb cffunction

aktualisieren 2/22/2011

Marc Esher of MXUnit fame found the exact same bug in a different context. Seine Lösung beinhaltet eine große Schleife über eine Abfrage, die gelöst wird, indem von query="name" zu from="1" to="#name.recordcount#" index="row" gewechselt wird. Ein weiterer Ansatz, der unter Verwendung von <cfthread> innerhalb der Schleife als solche funktioniert:

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

Dies ist sehr effektiv, wenn Sie Situationen führen, in denen man die Dinge in der Schleife wie Abfragen und <cfmodule> innerhalb <cffunction> tun müssen, so dass die verbrauchte Speicher nur für diese Iteration.

Alt Question

der Hoffnung, jemand anderes kann mir bestätigen oder sagen, was ich falsch mache. Ich bin in der Lage, eine laufende OOM konsistent zu reproduzieren, indem ich die Datei oom.cfm aufruft (siehe unten). Mit jconsole kann ich sehen, dass die Anfrage Speicher verbraucht und sie nie wieder freigibt, bis sie abgeschlossen ist. Das Problem scheint <cfmodule> innerhalb von <cffunction> zu rufen, wo, wenn ich den <cfmodule> Aufruf auszeichne, werden Sachen Müll gesammelt, während die Anforderung ausgeführt wird.

Coldfusion-Version: 9,0,1,274733

JVM Argumente

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 (dies nennt template.cfm unten - 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> 
+0

Ich bin auf Gelegenheiten gestoßen, bei denen Multithreading mein Gedächtnis verlor, und schrieb ein paar hier auf SO. Würde mich nicht überraschen, wenn das ähnlich wäre. –

+1

Was passiert, wenn Sie nur den cfmodule-Aufruf innerhalb der Schleife ausführen und die Funktion vollständig auslassen? –

+0

@Adam Tuttle: guter Kommentar, hatte nicht so getestet. Wenn ich versucht, Speicherabfrage während der Anfrage auftritt, so zeigt noch immer auf '' innerhalb ''. – orangepips

Antwort

5

Ich habe nicht in diese vor laufen, aber hier ist das, was ich denke, ist los :

Jedes Mal, wenn cfmodule aufgerufen wird, wird ein neuer Speicherbereich dafür erstellt (whic h, IIRC, ist der Hauptunterschied zwischen ihm und cfinclude). Da Sie das cfmodule innerhalb der Funktion aufrufen, gehört der Speicherbereich cfmodule technisch zum Speicherbereich dieser Funktion. Der Speicher der Funktion ist vor der Speicherbereinigung geschützt, bis die Funktion beendet ist. Ergebnis: Heap füllt, und Sie erhalten einen OOM-Fehler.

Ich glaube nicht, dass das Aufrufen eines Speicherlecks korrekt ist, da es sich korrekt verhält, und wenn die Funktion beendet ist, kann der Garbage Collector den Speicher löschen. Ich kann jedoch sehen, wie es unbequem sein könnte.

+1

+1 weil das mein Verdacht ist. Es ist jedoch ein Fehler. Ohne den Modulaufruf wird die Speicherzuweisung * der Funktion * Garbage während der Anfrage gesammelt. Das Hinzufügen eines cfmodule-Aufrufs innerhalb davon sollte daher einen Teil des zugewiesenen Speichers der Funktion bilden und für die Garbage-Collection verfügbar sein, wenn die Funktion den Gültigkeitsbereich verlässt (z. B. die Schleife iteriert), aber dies geschieht eindeutig nicht. Versuchen Sie ernsthaft den Testfall für sich selbst, mit und ohne das Modul innerhalb der Funktion, und Sie werden sehen. – orangepips

+0

Der Speicherbereich des CF-Moduls ist nicht an eine benannte Variable gebunden, er geht nicht aus dem Gültigkeitsbereich, bis der Funktionsaufruf endet. Schlechtes Design oder Bug? Persönlich denke ich, es ist nur schlechtes Design, aber könnte falsch sein. –

+0

Dies als die Antwort zu markieren, aber immer noch insgesamt bitter (nicht auf den Antworter kümmern Sie sich). – orangepips

3

Dieses Problem manifestiert sich leider mit vielen Tags. Ich habe das mit cflock in cfthread gesehen.Schreiben Sie eine sehr lange laufende Schleife in einen cfthread, der cflock verwendet, Sie werden schließlich nicht genügend Speicher haben. Es dauert lange, aber es passiert. Ich wette, dass das Aufbewahrungsproblem auch bei regulären Anfragen existiert, aber Sie haben normalerweise keine Schleife, die hunderttausende Male mit einem cflock läuft, so dass niemand merkt.

berichten ich diesen Fehler vor langer Zeit, aber es wurde nie festgelegt: http://www.elliottsprehn.com/cfbugs/bugs/83359

Die beste Lösung für jetzt cfmodule in einer Schleife wie diese nicht zu verwenden ist. Benutzerdefinierte Tags waren eigentlich nicht dazu gedacht, in einer einzigen Anfrage 20k Mal aufzurufen. Sie werden stattdessen UDFs verwenden wollen. cfmodule ist sowieso extrem teuer und die Verwendung einer UDF wird merklich schneller.

+0

Sphrehn: +1 Ich habe dein Beispiel zur ursprünglichen Frage hinzugefügt.Ich bin der Meinung, dass die Vorstellung, den Aufruf so oft zu machen, schlecht ist, aber es geht auch darum, mit einer 8 oder 9 Jahre alten Codebase zu arbeiten, wo viel Code geschrieben wird, der mit cfmodule/als custom aufgerufen wird Etikett. – orangepips

0

Hier ist eine Diskussion über eine möglicherweise Coldfusion-Version 9 cfc Speicherverlust Problem verbunden: http://forums.adobe.com/thread/1034324?start=0&tstart=0

diesen Fehler Bericht darüber Siehe: https://bugbase.adobe.com/index.cfm?event=bug&id=3124148

Ich glaube nicht, dass Adobe ein Update für verion 9.01 freigegeben, aber Angeblich ist dieses Problem in Version 10 behoben. Es gibt für die meisten Leute (je nach Umfang ihres Problems) Workarounds, ähnlich wie hier beschrieben.

+0

Dies sollte ein Kommentar zur OP-Frage sein, da sie nicht versucht, sie zu beantworten – Yaroslav