Memory Leak Looping cfmodule inside cffunction - memory-leaks

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>

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.

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.

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.

Related

ColdFusion / IIS / Redirect Limit?

I have a ColdFusion script which performs a task and then redirects to itself using the <cflocation> tag, passing in the next ID to be processed. The script stops working after EXACTLY 51 rows. I thought it was a bug in the code, so I updated the ID to be process to 52, and it runs from ID 52 through 102 and stops. Again, 51 rows exactly.
does anyone know if there is some limit in ColdFusion on the cflocation tag? Or could this be something IIS is doing?
When I use JavaScript window.location method, it works fine and does not stop until the end - as expected.
Updated - Explanation
The reason the script redirects to itself after each ID is processed is because ColdFusion does not release variables/memory back to the JVM until after the request is complete. So, for a request that performs several hundred complicated tasks, the memory usage continues to grow until the request officially completes. This causes an ERROR OUT OF MEMORY in the JVM. From what I understand, the best way to correct this is to split the items out into separate requests, that way ColdFusion will release the request variables/memory back to the JVM. Thus, why we are processing 1 item and then redirecting to self passing in the next ID to process. This is to keep ColdFusion seeing the requests as unique and keep memory consumption down.
It's an "ugly hack" but, maybe you'd like to try in case you can't find another option.
I was able to test and run this until completion as a scheduled task by executing curl from ColdFusion, so it requires curl available.
<cfparam name="url.id" default="0" />
<cfset url.id = url.id + 1 />
<!--- // your task code --->
<cffile
action = "append"
file = "C:\inetpub\wwwroot\foo\redir-log.txt"
output = '#url.id#'>
<!--- // your task code --->
<!--- // condition to end the loop --->
<cfif (url.id lt 300)>
<cfset args = [
'http://127.0.0.1:53227/redir.cfm?id=#url.id#'
] />
<cfexecute
name="curl"
arguments="#args#"
variable="output"
errorVariable="error"
timeout="0"
/>
<cfdump var="#output#" />
<hr />
<cfdump var="#error#" />
<hr />
</cfif>
I am not sure about a limit being there in ColdFusion/IIS, but I think browsers have a fail safe in order to restrict infinite loop. In my browser(Chrome), it seems the limit is 19.
The ways to overcome this is to make sure that the HTML loads, so that we do not confuse the session. Then redirect using either of the following.
window.location
<meta http-equiv="refresh" content="0;url=http://example.com">.

Random failure of selenium test on test server

I'm working on a project which uses nodejs and nighwatch for test automation. The problem here is that the tests are not reliable and give lots of false positives. I did everything to make them stable and still getting the errors. I went through some blogs like https://bocoup.com/blog/a-day-at-the-races and did some code refactoring. Did anyone have some suggestions to solve this issue. At this moment I have two options, either I rewrite the code in Java(removing nodejs and nightwatch from solution as I'm far more comfortable in Java then Javascript. Most of the time, struggle with the non blocking nature of Javascript) or taking snapshots/reviewing app logs/run one test at a time.
Test environment :-
Server -Linux
Display - Framebuffer
Total VM's -9 with selenium nodes running the tests in parallel.
Browser - Chrome
Type of errors which I get is element not found. Most of the time the tests fail as soon the page is loaded. I have already set 80 seconds for timeout so time can't be issue. The tests are running in parallel but on separate VM's so I don't know whether it can be issue or not.
Edit 1: -
Was working on this to know the root cause. I did following things to eliminate random fails: -
a. Added --suiteRetries to retry the failed cases.
b. Went through the error screenshot and DOM source. Everything seems fine.
c. Replaced the browser.pause with explicit waits
Also while debugging I observed one problem, maybe that is the issue which is causing random failures. Here's the code snippet
for (var i = 0; i < apiResponse.data.length; i++) {
var name = apiResponse.data[i];
browser.useXpath().waitForElementVisible(pageObject.getDynamicElement("#topicTextLabel", name.trim()), 5000, false);
browser.useCss().assert.containsText(
pageObject.getDynamicElement("#topicText", i + 1),
name.trim(),
util.format(issueCats.WRONG_DATA)
);
}
I added the xpath check to validate if i'm waiting enough for that text to appear. I observed that visible assertion is getting passed but in next assertion the #topicText is coming as previous value or null.This is an intermittent issue but on test server happens frequently.
There is no magic bullet to brittle UI end to end tests. In the ideal world there would be an option set avoid_random_failures=true that would quickly and easily solve the problem, but for now it's only a dream.
Simple rewriting all tests in Java will not solve the problem, but if you feel better in java, then I would definitely go in that direction.
As you already know from this article Avoiding random failures in Selenium UI tests there are 3 commonly used avoidance techniques for race conditions in UI tests:
using constant sleep
using WebDriver's "implicit wait" parameter
using explicit waits (WebDriverWait + ExpectedConditions + FluentWait)
These techniques are also briefly mentioned on WebDriver: Advanced Usage, you can also read about them here: Tips to Avoid Brittle UI Tests
Methods 1 and 2 are generally not recommended, they have drawbaks, they can work well on simple HTML pages, but they are not 100% realiable on AJAX pages, and they slow down the tests. The best one is #3 - explicit waits.
In order to use technique #3 (explicit waits) You need to familiarize yourself and be comfortable with the following WebDriver tools (I point to theirs java versions, but they have their counterparts in other languages):
WebDriverWait class
ExpectedConditions class
FluentWait - used very rarely, but very usefull in some difficult cases
ExpectedConditions has many predefinied wait states, the most used (in my experience) is ExpectedConditions#elementToBeClickable which waits until an element is visible and enabled such that you can click it.
How to use it - an example: say you open a page with a form which contains several fields to which you want to enter data. Usually it is enought to wait until the first field appears on the page and it will be editable (clickable):
By field1 = By.xpath("//div//input[.......]");
By field2 = By.id("some_id");
By field3 = By.name("some_name");
By buttonOk = By.xpath("//input[ text() = 'OK' ]");
....
....
WebDriwerWait wait = new WebDriverWait( driver, 60 ); // wait max 60 seconds
// wait max 60 seconds until element is visible and enabled such that you can click it
// if you can click it, that means it is editable
wait.until( ExpectedConditions.elementToBeClickable( field1 ) ).sendKeys("some data" );
driver.findElement( field2 ).sendKeys( "other data" );
driver.findElement( field3 ).sendKeys( "name" );
....
wait.until( ExpectedConditions.elementToBeClickable( buttonOK)).click();
The above code waits until field1 becomes editable after the page is loaded and rendered - but no longer, exactly as long as it is neccesarry. If the element will not be visible and editable after 60 seconds, then test will fail with TimeoutException.
Usually it's only necessary to wait for the first field on the page, if it becomes active, then the others also will be.

Remove and restore Scope from digest cycles

Is there a way to remove a scope from the digest cycles? In other words, to suspend/resume a scope digest cycle?
In my case, I have all pages already loaded, but not all of them visible. So I'd like to suspend the ones that aren't visible to avoid useless processing. I don't want to use ng-view + $route, I don't want/need deep-linking.
I saw this thread and arrived to this fiddle. It probably does the work, but it's pretty invasive and not very framework-update-friendly.
Is there any other solution like a $scope.suspend() and scope.resume()? Or a less invasive one (from framework perspective)? I'm currently thinking about $destroy and $compile cycles.
I've ran into the same problem and I found an interesting solution that doesn't interfere (too much) with AngularJS. Add this to the scopes you want to disable:
var watchers;
scope.$on('suspend', function () {
watchers = scope.$$watchers;
scope.$$watchers = [];
});
scope.$on('resume', function () {
scope.$$watchers = watchers;
watchers = null;
});
Then, you can disable a scope and its children with: scope.$broadcast('suspend') and bring it back with scope.$broadcast('resume').
As the framework stands today there are no methods to suspend / resume digest on a scope. Having said this there are several techniques that one can use to limit number of watches that are executed as part of a digest cycle.
First of all, if parts of a screen are hidden anyway you could use the ng-switch family of directives thus removing invisible parts completely from the DOM.
Secondly, if a digest cycle is triggered from your directive via $apply and you want to limit watches re-evaluation to child scopes you could call $digest instead of $apply.
Then, yes, one could destroy and re-create scopes as described in the discussion you've linked to. But, if you are already hiding parts of the DOM it sounds like ng-switch might be a better option.

how to make sure a Coldfusion object is only created once?

I have a scheduled task which should run every minute. To block the file from being called from outside, I want to compare host and calling IP adress like so:
<cfif NOT structKeyExists( "variables", caller )>
<cfset variables.caller = createObject("java", "java.net.InetAddress")>
</cfif>
<cfif variables.caller.getLocalHost().getHostAddress() EQ cgi.remote_addr>
// run task
</cfif>
Question:
I'm not really used to working with objects in Coldfusion, so would this be a way to make sure the object is created once and re-created every minute when the task is being called? Since this is running in my admin section, should I create the object on application scope right away?
Thanks for some input!
When you run a request even if the request is a scheduled task, all the variables are destroyed when the request has been completed. Only variables like session, application, and server persist between requests.
One approach to making sure that pages only run on the machine that they are on is to:
<cfif cgi.remote_addr EQ "127.0.0.1">
// run task
</cfif>

ColdFusion threads: looping session variables + sleep

hey guys I'm trying to create a timer which counts the time spent on a page using a thread heres what I have so far:
<cfset session.time=0>
<cfthread name="timer" action="run">
<cfscript>
counter = 0;
while (counter <9000) {
sleep(1000);
session.time++;
counter ++;
}
</cfscript>
</cfthread>
page 2:
<cfoutput>#session.time#</cfoutput>
page 2 gives me 0 every time anyone see a problem?
edit:
I changed line 1 of my code to <cfset session.time=100> and now page 2 says 100, its like the stuff inside the cfscript loop isn't reassigning session.time
This works for me.
Are you sure you are using the Developer or Enterprise edition of ColdFusion and the threads have actually kicked off? I think only those editions support multi-threading.
One way to do verity your threads working is to use cfstat - you should see one request running even though your page has returned.
Another is to write output from your spawned thread - use the code snipped below to write to System.out - ideally you'll need to have CF running as a console task to do this.
<cfset session.time=0 />
<cfthread name="timer" action="run">
<cfscript>
counter = 0;
while (counter <9000) {
sleep(1000);
session.time++;
sys = createObject("java", "java.lang.System");
sys.out.println("*** [DEBUG] - #timeformat(now(),'HH:mm:ss' )# - session.time=#session.time# ");
counter ++;
}
</cfscript>
</cfthread>
Your code works fine for me. You have got an Application.cfm page setup to enable session management i.e:
<cfapplication name="#hash(getCurrentTemplatePath())#"
sessiontimeout="#createTimeSpan(0,0,20,0)#" sessionmanagement="true"/>
Code executed inside a thread has its own scope, including session. I would set a variable within the tread and then access it from within the threads scope.
i.e.
Change session.time++; to thread.time++; and then use cfthread[timer].time to get the thread's time.
Although this may not hold if you enable session management like some of the other posts discuss.

Resources