Download Firefox 3 Today!

You will probably hear this elsewhere also. But, considering how indespensible Firefox has come to be to me as a Web Developer, I couldn't not tell you about this.

java.lang.ref.SoftReference in CFML

So, one of the coolest things I learned at the conference was about how Transfer does it's caching. Part of that is using the Java SoftReference class. Soft reference objects are cleared at the discretion of the garbage collector in response to memory demand. Let me show you what I mean.

<cfloop query="OrderedUserQry">
   <cfif NOT structKeyExists(application.UserCache, OrderedUserQry.UserIdentity)>
      <cfset user = dbService.getUserByID(OrderedUserQry.UserID) />
      <cfset application.UserCache[OrderedUserQry.UserIdentity] = user />
   </cfif>
   <cfset application.maxUserInt = OrderedUserQry.UserIdentity />
</cfloop>

This code mimics a caching mechanism that would put a hard reference in the application.UserCache to a "User" object. I just ran this repeatedly this morning until CF would not respond with anything but "java.lang.OutOfMemoryError". Fun yeah?

Change that code to this:

<cfloop query="OrderedUserQry">
   <cfif NOT structKeyExists(application.UserCache, OrderedUserQry.UserIdentity)>
      <cfset user = dbService.getUserByID(OrderedUserQry.UserID) />
      <cfset application.UserCache[OrderedUserQry.UserIdentity] = CreateObject('java','java.lang.ref.SoftReference').Init(user) />
   </cfif>
   <cfset application.maxUserInt = OrderedUserQry.UserIdentity />
</cfloop>

And you can run it all day long. I also created a page to go through the cache and get rid of keys that the soft-referenced object had been GCed. With help from SoftReference, the JVM was able to reclaim memory as needed. So, after I got to about 100,000 users having been put into cache, I ran the culling page and the cache only had arount 18,000 keys left.

<!--- Culling Code --->
<cfloop list="#StructKeyList(application.UserCache)#" index="key">
   <cfset user = application.UserCache[key].get() />
   <cfif NOT structKeyExists(variables,'user')>
      <cfset structDelete(application.UserCache,key) />
   </cfif>
</cfloop>

I definitely will be using this in caching systems in the future. There may be cases where you want a hard-reference cache. But, there are plenty more I think, where it would be fine if some objects in your cache were GCed to give the JVM the memory it needs.

BlogCFC was created by Raymond Camden. This blog is running version 5.6.002.