2011-01-07 8 views
8

Googlersi, którzy mają zrzut sterty z korzeniami coldfusion.runtime.CFDummyComponent czytają.Wyciek pamięci w pętli cfmodule wewnątrz cffunction

Aktualizacja 2/22/2011

Marc Esher of MXUnit fame found the exact same bug in a different context. Jego rozwiązanie obejmuje dużą pętlę nad zapytaniem rozwiązanym przez przejście z query="name" do from="1" to="#name.recordcount#" index="row". Innym rozwiązaniem, które działa korzysta <cfthread> wewnątrz pętli jako takie:

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

Jest to bardzo skuteczne, gdy napotkasz sytuacji, gdy trzeba robić rzeczy wewnątrz pętli jak zapytaniami i <cfmodule> wewnątrz <cffunction> tak, że pamięć zużywana jest tylko dla tej iteracji.

Old Pytanie

nadzieję, że ktoś inny może potwierdzić lub powiedz mi, co robię źle. Jestem w stanie konsekwentnie odtwarzać OOM, wywołując plik oom.cfm (pokazany poniżej). Używając jconsole, widzę, że żądanie zużywa pamięć i nigdy nie zwalnia jej aż do zakończenia. Wydaje się, że problem polega na wywołaniu <cfmodule> wewnątrz <cffunction>, gdzie w przypadku komentowania połączenia <cfmodule> rzeczy są gromadzone podczas działania żądania.

ColdFusion wersja: 9,0,1,274733

JVM Argumenty

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 

Przypadek Testowy

oom.cfm (wymaga to template.cfm poniżej - 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! ---> 

Aktualizacja # 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

Znam przypadki, w których wielowątkowość zabijała moją pamięć, i wysłałem tu kilka na SO. Nie zdziwiłbym się, gdyby to było podobne. –

+1

Co się stanie, jeśli wykonasz wywołanie cfmodule wewnątrz pętli, całkowicie pomijając funkcję? –

+0

@Adam Tuttle: dobry komentarz, nie testowałem w ten sposób. Kiedy próbowałem odzyskać śmieci podczas żądania, tak nadal wskazuje na '' wewnątrz ''. – orangepips

Odpowiedz

5

I już nie napotkasz tego wcześniej, ale tutaj jest to, co myślę jest grane :

Za każdym razem, gdy wywoływany jest cfmodule, tworzona jest dla niego nowa pamięć (whic h, IIRC, jest główną różnicą między nim a cfinclude). Ponieważ wywołujesz cfmodule w obrębie funkcji, pamięć pamięci cfmodule technicznie należy do tej przestrzeni pamięci. Pamięć funkcji jest chroniona przed czyszczeniem, dopóki funkcja nie zostanie wykonana. Wynik: wypełnia sterty, a otrzymasz błąd OOM.

Nie sądzę, że wywoływanie tego błędu w pamięci jest prawidłowe, ponieważ zachowuje się poprawnie, a po zakończeniu działania, moduł czyszczenia pamięci może usunąć wstrzymanie tej pamięci. Jednak widzę, jak może to być niewygodne.

+1

+1, ponieważ jest to również moje podejrzenie. Jest to jednak błąd. Bez wywołania modułu przydział pamięci funkcji * to * śmieci zebrane podczas żądania. Zatem dodanie wywołania cfmodule w jego obrębie powinno uczynić go częścią przydzielonej mu pamięci i być dostępne dla funkcji czyszczenia pamięci, gdy funkcja wykracza poza zakres (np. Pętla iteruje), ale tak się nie dzieje. Poważnie spróbuj testu dla siebie, zi bez modułu wewnątrz funkcji, a zobaczysz. – orangepips

+0

Miejsce pamięci cfmodule nie jest dołączone do nazwanej zmiennej, nie wykracza poza zakres, dopóki nie zakończy się wywołanie funkcji. Zły projekt lub błąd? Osobiście uważam, że to po prostu zły projekt, ale może się mylić. –

+0

Zaznaczając to jako odpowiedź, ale nadal jestem zgorzkniały (nie w twoim umyśle). – orangepips

3

Ten problem manifestuje się z wieloma tagami niestety. Widziałem to z cflock wewnątrz cfthread.Napisz bardzo długą pętlę w cfthreadu, która używa cflock, w końcu skończy Ci się pamięć. To zajmuje dużo czasu, ale to się dzieje. Założę się, że problem retencji istnieje również w zwykłych żądaniach, ale zazwyczaj nie ma pętli, która działa setki tysięcy razy z cflockiem wewnątrz, więc nikt nie zauważy.

zgłosiłem ten błąd już dawno temu, ale nigdy nie został ustalony: http://www.elliottsprehn.com/cfbugs/bugs/83359

Najlepszym rozwiązaniem jest teraz nie używać cfmodule wewnątrz pętli tak. Znaczniki niestandardowe nie były przeznaczone do wywoływania 20k razy w jednym żądaniu. Zamiast tego będziesz chciał używać UDF. cfmodule i tak jest bardzo kosztowne, a korzystanie z UDF będzie zauważalnie szybsze.

+0

Sphrehn: +1 Dodałem twój przykład do pierwotnego pytania.Uzgodniono, że pojęcie wykonywania połączenia wiele razy jest złe, ale jest to również kwestia pracy z podstawą kodu, która ma 8 lub 9 lat, gdzie jest napisane dużo kodu, który oczekuje na wywołanie za pomocą cfmodule/as custom etykietka. – orangepips

0

Oto omówienie możliwie związanego wersji ColdFusion 9 CFC problemu wycieku pamięci: http://forums.adobe.com/thread/1034324?start=0&tstart=0

Zobacz ten raport o błędzie na nim: https://bugbase.adobe.com/index.cfm?event=bug&id=3124148

Nie wierzę Adobe wydała poprawkę do niemieckiej wersji 9.01, ale podobno ten problem został rozwiązany w wersji 10. Istnieją rozwiązania, które w przypadku większości osób (w zależności od zakresu problemu) są obejścia tego problemu, w przeciwieństwie do tego, co zostało tutaj opisane.

+0

To powinno być komentarzem do pytania OP, ponieważ nie chce na nie odpowiedzieć – Yaroslav