I just released a 1.12 update to my varscoper tool. I’ve added new tags to the parsing engine, added XML output support, and fixed some bugs related to directory parsing in CF6. Thanks to Kola Oyedegi for help with XML output and Dmitriy Goltseker for fixing directory processing. Thanks to everyone who helped to refine the list of tags that create variables. The additions are below. You can also download 1.12 here , or get it via SVN on riaforge.
As part of the development effort on my var-scoping tool I have been trying to identify all of the tags that can create variables. I have yet to find a comprehensive listing of tags, so I’m hoping that people can leave comments here to expand the list.
Here’s my partial list to start with (yes I know it’s small), along with the parameter that specifies the variable name. Please comment on my blog and add on any that I’ve missed.
That’s right, my varScoper tool now supports cfml written within cfscript blocks. Please note that this is still somewhat experimental, but seems to handle quite a few scenarios.
After looking at Zac’s code, I decided to take it to the next level and complete the code required to identify variables created within cfscript blocks.
The code will even ignore variables created within comments, but unfortunately does not include the ability to identify the line number of the variable (which it does within tags). You can still jump directly to the method, but you’re on your own to find the variable.
You can even identify variables created within for loops and if/else blocks. Here’s an example…
for(correctLoop=1;correctLoop LTE 10; correctLoop=correctLoop+1) correctSimpleVar = correctLoop;
In this example correctLoop, and correctSimpleVar will both be identified with the tool.
For those of you who aren’t aware of varscoper, it is a code analyzer that will look for variables without a var statement that exist within a cffunction. I released the tool last July and cfscript support has been the #1 request.
Additionally, I am now hosting the project at RIAforge at http://varscoper.riaforge.org/, you can look there for SVN access.
Please take a minute to test out the code and please let me know ASAP if you can find any cases that the cfscript code doesn’t cover.
I have interviewed quite a few people lately for a few positions at my company. An interesting thing that I have noticed is that the majority of people I interview seem to think that session variables ALWAYS expire on browser close. However in a default CF install, session variables will persist even after a browser is closed and re-opened. This could mean that your users continue to be “logged in” to your application even after they close their browser.
The default behavior of a ColdFusion installation does not use per-session cookies in a browser, it uses persistent cookies instead. The difference being that per-session cookies are stored in client memory and are destroyed on browser close where persistent cookies are stored on disk and are available after a browser has been closed an opened.
There are reasons to use both per-session cookies as well as persistent cookies, but you should be aware of the difference. In a secure application, users generally expect that their session will end on browser close so you should be careful to enforce this behavior.
How do I change this???
There are a few ways to accomplish per-session cookie management in your application. One approach is to enable “Use J2EE session variables” in ColdFusion administrator, but you can also accomplish this in code. Take a look at this knowledgebase article for an extended explanation. – (Try this updated link, not the same article, but a good explanation – Adobe KB)
I have an immediate need for Senior ColdFusion developers in Emeryville, CA. I’m looking to fill 3 full time positions and 5 contract positions. Applicants should have a minimum of 3-5 years of development experience with CF, strong understanding of CFCs and Object Oriented concepts, and preferably experience on at least one large project with mach-ii or model-glue.
All positions will need to report on site at our offices in Emeryville. The name of the company is Planitax , and we have a hosted software solution targeted to tax departments in Fortune 1000 corporations. We have a robust client base (intel, at&t, sun for example) and we are growing rapidly. The application is very mature and it would be a great opportunity to work with some top notch developers, and explore advanced concepts. Pay is extremely competitive, and we have a great work environment.
Please contact our human resources department at firstname.lastname@example.org if you are interested in applying. Please NO recruiters.
In part III of my memory leak posts, I will attempt to show an example of how variable references can increase within in the heap on every request. If you would like to know more about the tools I used to identify the problem, or would like to follow along with the example you should take a look at my previous posts,
"ColdFusion Memory Leaks: Part I – profiler introduction"
"ColdFusion Memory Leaks: Part II – variables scope"
Note: The example that I will demonstrate is 90% complete. It is similar to the behavior that I experienced in my application, but not as severe. This only works in specific circumstances, where my problem appeared 100% of the time. Unfortunately, this is the closest I could come without including hundreds of thousands of lines of code.
For this example, we will expand the case that I demonstrated in the variables scope example. We will use the same test.cfc as the previous example.
Next we will need to expand the cfm page, we’ll make the following modifications.
- add session timeout of 10 seconds (to see results quickly)
- only load test.cfc into application on the first request
- create an array on the session
- create a new instance of test.cfc locally, and append it to the array on the session
creating a new session completed request - session size = #arrayLen(session.sessionArray)# reset application.test (this clears all memory references)
What should we expect in this example? (feel free to correct me if you think this should be different)
- 1 instance of test.cfc should be loaded into application
- foo exists in variables scope and creates a reference to an array of 100 instances of test.cfc (this is the example from Part II and should be destroyed at the end of the request)
- an instance of test.cfc will be added to the session on every request. (5 request in a session = 5 test.cfc)
- when the session expires, the array should be cleaned from the heap.
Now for a flash movie that will show the results of what actually happens (my apologies if this is rushed, there’s quite a bit going on in a short timeframe)
What happened??(also, how you can follow along if you execute the example)
- On the first request, test.cfc is loaded into the application at the same time a new session is created
- Every request loads an extra 100 references to test.cfc (which should only exist in variables scope)
- The session that loads the cfc into application scope (and only this session) will persist all the references for the life of the application
- All additional sessions will hold their references for the life of the session
- Adding a structure to session instead of a cfc will create the proper behavior
Why does this happen? I can’t tell you, I’m hoping the community, or adobe will be able to figure that out. Some other notes that I would like to add…. The behavior occurs if it is a struct OR an array on the session. The behavior also occurs if all the cfcs are different (I used test.cfc for all references to keep the example simple). If you reload application.test, the references will be cleaned up, but the behavior will occur for the session associated with the request that created application.test.
How do I fix this in my application???
I am not going to recommend a solution for this because I haven’t found a "magic bullet" yet. I am also not going to recommend a solution because every application is unique, and every memory leak is different. I will however tell you that my problem was very similar to this. We were keeping a history stack on the session that consisted of an array of simple beans. Converting the beans to structures, solved a large part of the problem. This isn’t always an option if you are storing complex objects on the session. I’m very interested to see if anyone else having a similar problem is storing cfcs on a session, as the root cause seems to be a wacky combination of instantiating cfcs on multiple scopes within a request.
In part II of my memory leak posts, I will attempt to demonstrate a simple example of how the CFML runtime engine can cause memory leaks. If you would like to know more about the tools I used to identify the problem, or would like to follow along with the example you should take a look at my previous post, "ColdFusion Memory Leaks: Part I – profiler introduction"
For those of you that have ever experienced memory leaks, have there been cases where you have been convinced that the problem is not your code? Well, you may actually be right. This example will show a very simple case, then I will try to build on this to show a more problematic example in my next post.
The first part of the example is to create a simple .cfc. This cfc will have 2 methods: init() which returns itself, and doSomething() which will return an array of 100 instances of itself.
The next part of the example will be a simple cfm file. This file will create 1 instance of the test.cfc and load it into application scope, then it will call the doSomething() function and set the result to a local variable that resides in variables scope.
foo is an array of #arrayLen(foo)# elements
What should we expect from this example? Well, we should have 1 instance of test.cfc persisted in the heap. We will create 100 references to test.cfc, but those should only exist in the heap until the end of the request. The garbage collector should pick them up immediately, as all references should only exist for the request.
Now, to show the results of the test, I created a movie that will show the behavior, watch it to see what actually happens.
What happened? As you can see, 101 instances were persisted in the heap, and not released. These instances will live for the life of the application and NOT for the life of the request as intended. In this case we should only see 1 instance of the cfc in the heap. Here are some of the behaviors I observed.
- references to objects created in application scope will be kept alive if they are
set to a reference in the variables scope.
- Setting the variable in variables scope to empty string " "
will destroy the reference.
- Setting the reference in request scope will clean up the reference correctly.
- Calling structClear(variables)
in onRequestEnd.cfm will destroy unwanted references tied to variables scope
- The reference retained in the variables scope only seems
to apply to the last request to the.cfm file (will not grow)
As you can see, this isn ‘t a horrible memory leak because it won’t grow continually,
but it could cause unwanted objects to be persisted in memory. This IS a simple example, and
I’m working to create a similar, but more complex example to build on this that will show that cfc references can grow in memory on every request. Stay Tuned.
Over the last year or so I’ve been dealing with memory leaks in ColdFusion. Some have been code related, but others seem to be issues with the way ColdFusion handles garbage collection of CFCs. Recently, we’ve made some breakthroughs at my company, so I thought I would share the steps that we took to identify memory leaks along with some interesting behaviors that we observed.
Hopefully, when I am finished, you will be on your way to changing your memory profile to look something like this… (This is an actual application profile under load)
In this post, I will show you the steps that I used to setup an environment that enabled me to identify the problem.
Step 1: configure your jvm: 5.0 is the way to go
The first thing that I tried was to use a profiling tool (i.e. jprobe or yourkit) against my existing coldfusion/jrun instance. This proved to be a mistake because the profiler added so much overhead to the jvm that the application became unresponsive. The solution was to use a Java 5 jvm. Jrun does not support Java 5 (JVM 1.5), but for the most part your application should run to the point that you can profile effectively.
Step 2: running with BEA Jrockit
For our example, I will suggest using the 1.5 jrockit jvm provided by BEA. The reason for this is because they have some powerful profiling tools that I will talk about later.
First, go to the following URL, and install the Jrockit 5.0 JDK
(For the rest of the example I will assume that you installed the JDK at C:\Program_Files\Java\jrockit-R26.4.0-jdk1.5.0_06\ )
you will also need to download a Jrockit Mission Control 1.0 license key. (you may need to register for that), save this file named as license.bea and move it to the following folder.
After that, modify your jvm.config file and change java.home to the following… (make sure to use forward slashes)
to enable profiling, you will need to add the following to your jvm args… (specify any port that you want)
Now restart the CF service and you are ready to go.
Step 3: memory leak detector
Now for the fun part… the Jrockit JDK ships with a tool called "Memory Leak Detector", To start using this, browse to the following folder…
Then double click on MemoryLeakDetector.jar (you may have to run it from the command line if that doesn’t work). The tool should start, and you should be able to specify the server and port (that you specified in jvm.config).
The next step is critical to effectively profile a ColdFusion application. From what I’ve observed, Internally, most of your variable data will be stored within objects of type coldfusion.runtime.variable. CFC classes don’t hold much data, so they take up a very small percentage of the jvm heap. We need to change the memory leak detector settings to look at small heap sizes. To do this, browse to File/Preferences/Trend and change "lowest heap usage to report" to 0.
Step 4: example
To show you how to use the memory leak detector, we will create an example, for this example I will create a cfc, this cfc has 2 methods, init() that returns itself, and doSomething() which will load 100 instances of itself into the variables scope of the object.
Next, create a simple cfm page that will load the cfc into memory and call the doSomething() function. Calling this .cfm page should create 101 instances of test in the application scope (1 loaded into application, and 100 loaded within itself)
After you have executed the page, return to your memory leak detector and filter by "cf" (you can also filter by "cold" to see internal ColdFusion representations). You should now see something like this in the memory leak detector.
you will now see that we have created 101 instances of test.cfc in the memory heap (along with a reference to test.cfm that it is keeping alive, plus the empty classes it uses internally to identify the init() and doSomething() methods.
If you have made it to this point, you are on your way to profiling your application. If you leave the memory leak detector running under load, it will eventually track the growth of objects, and can be used to pinpoint potential problems. In my next post I will identify some of the potential problem behaviors of the ColdFusion engine, and how it can potentially "leak" object references in simple examples.
Credits and Reading materials
The basis of this strategy is outlined in greater detail in a pdf book created by Grant Straker. He focuses on other aspects of optimizing cf performance besides memory usage as well. If you are headed to Max, then I would highly recommend checking out his talk.
His pdf book is available at…
In my opinion this could be the most valuable $50 that you will ever spend on CF knowledge, and is well worth the money.
Last week I learned that cfschedule has some annoying behavior when trying to call the delete action. If a scheduled task tries to delete itself (or update itself) through the cfschedule tag, it won’t actually delete the task and will continue to run until the server is restarted. This post describes a way for a scheduled task to delete itself.
This has been identified as a known issue in ColdFusion MX and is addressed in a TechNote. Macradobe suggests that we “Delete tasks through cf administrator” or “restart the cf server”. Neither one of these is an option for me if I want to programmatically delete my task.
The Adobe techNote is somewhat misleading, it turns out that delete does work through the cfschedule tag, but the problem arises when the scheduled task tries to delete itself.
The solution? Since cfschedule – delete works on a normal http request, but not on a “scheduled” http request, we need to make an asyncronous HTTP call from the task. This can be chieved using a cool tool called asyncHTTP written by Mark Mandell (Look at the blog posting here)
Now, within the request that is called from the scheduled task, I can include the following code.
The code to delete the scheduled task will now work…
Implementing this functionality allows us to process a queued stack in the background then delete the task when it’s complete. This is a powerful tool that allows us to execute code at a scheduled time, then continue executing until a condition has been met.
Today I am releasing version 1.0 of a project that I’ve been working on for a few weeks. It’s a cfc that can be used to parse cfm and cfc files and identify variables that haven’t been locally scoped within cffunctions.
varScoper can do the following….
- Find unscoped variables created with a cfset within a cffunction
- Find unscoped variables created with cftags (cfloop, cfquery, etc)
- Report line numbers and link directly to the line in the file
- Output to screen or csv
Hopefully everyone else will find this as useful as I do. There’s a link in my projects section to the project page, or you can follow this link.
You might be surprised at the results you find. I’ve been careful to scope my vars within the last few years, but I found an alarming number of potential problems in some of the code I was writing a few years ago when I first started with CFCs. In any case, try downloading the sample code, run it against your codebase, and do some housecleaning.
Here’s a screenshot