919 - 926 - 9847

Railo scope dumper

I'm presently trying to run down a memory (perceived) leak issue on an application that I've hosted for 3 years. In the past 3 months, this app has moved to the FarCry framework from a... less than stellar homebrew solution

At first, I thought it was Lucene shorting out, but I didn't have anything concrete beyond the amount of traffic hitting it. I installed FusionReactor, and although it's very helpful to watch the graphs, it still didn't give all that much accuracy into what was going on. Until...

A heap dump from yesterday revealed that railo.runtime.type.scope.ApplicationImpl had grown to 450 megs for just one site (the one converted recently). After asking around the Railo list, this object appears to be the application scope. Further suggestion was to loop over the keys, and use the built-in sizeOf and countOf functions to see what's going on (yay Railo!).

With some manual dumping of those keys, it appears that the cached HTML object types had grown far beyond expected. Way, far beyond. Ooops. So I cleared the cached objects, and poof, memory was manageable again.

So, on to a handy little file/CFC that will dump out scopes in Railo (I don't think these functions exist in Adobe CF, but I've not tested yet). Much thanks to Gert Franz, Michael Offner, Jay, and Peter Boughton (especially for those key loops Peter!)

First, you need this template. scopeDump.cfm


<!--- instantiate scope object --->
<cfset oGetScopeDetail=createObject("component", "scopeDump")>
<cfoutput>
<form action="" method="post">
<!--- set what scopes you want to dump --->
<select name="scope" id="scope">
    <option value="application">Application</option>
    <option value="session">Session</option>    
    <option value="cgi">CGI</option>
</select>

<input id="submit" name="submit" type="submit" value="GO!">
<cfif structkeyExists(form,"submit")>

<!--- You MUST get the struct to pass into the function --->
    <cfset stScope=oGetScopeDetail.getDetail(structGet(form.scope))>
    <cfif structkeyExists(stScope,'countOf')>
        <p>Count of #form.scope#: #stScope.countOf#</p>
    </cfif>
    <cfif structkeyExists(stScope,'sizeOf')>
        <p>Size of #form.scope#: #stScope.sizeOf#</p>
    </cfif>
<!--- Looping over the returned objects in the structure --->
    <cfif structkeyExists(stScope,'aItems')>
        <table border="1">
            <tr>
                <td>Item</td>
                <td>Count</td>
                <td>Size</td>
            </tr>
            <cfloop from="1" to="#arraylen(stScope.aItems)#" index="i">
                <tr>
                    <td>#stScope.aItems[i].name#</td>
                    <td>#stScope.aItems[i].countOf#</td>
                    <td>#stScope.aItems[i].sizeOf#</td>
                </tr>
            </cfloop>
        </table>
    </cfif>
</cfif>
</form>
</cfoutput>

You'll also need this little CFC, scopeDump.cfc


<cfcomponent displayname="scopeDump" >

    <cffunction name="getDetail" access="remote" returntype="struct">
        <cfargument name="scopeVar" required="yes" type="struct">
        
        <cfset var rStruct=structnew()>
        <cfset rStruct.countOf=numberformat(StructCount(arguments.scopeVar),',')>
        <cfset rStruct.sizeOf=numberformat(SizeOf(arguments.scopeVar),',')>
        <cfset var aItems=arraynew(1)>
        <cfset var stItems=structnew()>
        <cfset var tmp="">
        <cfloop item="CurItem" collection=#arguments.scopeVar#>
            <cfset stItems.name=CurItem>
            <cfif isStruct(arguments.scopeVar[CurItem])>
                <cfset stItems.countOf=numberformat(StructCount(arguments.scopeVar[CurItem]),',')>
            <cfelse>
                <cfset stItems.countOf=0>
            </cfif>
            <cfset stItems.sizeOf=numberformat(SizeOf(arguments.scopeVar[CurItem]),',')>
            <cfset tmp=arrayappend(aItems,structcopy(stItems))>
            <cfset tmp=structclear(stItems)>
        </cfloop>
        <cfset rStruct.aItems=aItems>

        
        <cfreturn rStruct>
    </cffunction>
</cfcomponent>

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
AJ Mercer's Gravatar Does this mean there is a caching issue with Farcry (on Railo)?
# Posted By AJ Mercer | 9/4/11 9:22 PM
Matthew Williams's Gravatar Nope, my fault entirely. I've not yet cached that much information for a site before. I really wish that we had more built in tools for this (no matter the engine), but it's really hard to see what's going on in real-time without something like FusionReactor. Basically, dmHTML was up to 350 megs of cache when set to 1000 objects (not the default! I had to specify this by extending dmHTML). I'm surprised that 1000 templates hit that much size, but... meh.

Now I just need to convince the app owner to spring for both a license for FR, and another 512 meg of memory or so ;).
# Posted By Matthew Williams | 9/4/11 9:43 PM