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.

Comments
Ben Nadel's Gravatar @Chris,

I'm glad you got the GC to actually kick in. Good to know this works. Mark's presentation on caching was excellent.
# Posted By Ben Nadel | 5/7/08 12:22 PM
phill.nacelli's Gravatar @Chris,

Thanks for blogging on this... I only got part of that session and didn't have great notes on this feature. Very cool indeed.
By the way, my shoes still have all that grease from Mickey's floor!!!

Cheers..
# Posted By phill.nacelli | 5/7/08 1:32 PM
Mark Mandel's Gravatar Chris,

Glad to hear you got something out of my presentations! :oD

You probably also want to look at java.lang.ref.ReferenceQueue so you can track which softReference objects have been reaped.

The original place I read about SoftReferences was at:
http://blogs.sanmathi.org/ashwin/2006/07/01/memory...

You may want to check that out too.

Enjoy!
# Posted By Mark Mandel | 5/8/08 12:23 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.6.002.