Select Page

Testing Performance Overhead Of Creating Java Classes In Lucee CFML

Cyberdime
Published: January 13, 2023

One of the most powerful features of ColdFusion is the fact that it is built on top of Java; and, at any time, we can reach down into the Java layer for additional functionality. The typical way in which we do this is to call createObject("java") and pass in a Java class name. Historically, I’ve tended to cache the returned Java class value, operating under the assumption that createObject() had a lot of overhead. But, I don’t think I ever based this assumption on any concrete evidence. As such, I wanted to perform a trite performance exploration regarding the createObject() function in Lucee CFML.

As with all low-level performance experiments, this should be taken with a grain of salt seeing as I’m running it on my machine with no production traffic. That said, my goal here isn’t to see absolute numbers but more to get a sense of relative performance between two different approaches.

To try this out, I’m going to experiment with a Static method on Java’s Long class: .toString(). In my first loop, I’m going to call createObject() within every iteration. Then, in my second loop, I’m going to use a cached instance of the LongClass.

ASIDE: When I say “instance” here, it’s a bit fuzzy – it’s the instance of the class definition, not an instantiated instance of the class. This has to do with the ColdFusion abstraction of Java.

Note that in the following code, I’m outputting one value within each loop as a means to make sure that the ColdFusion compiler isn’t trying to “optimize” the loop out of the code (seeing as it doesn’t really do anything).

<cfscript>
	trialCount = 5;
	iterations = 1000000;
	echo( "Trials: #trialCount#, Iterations: #numberFormat( iterations )# <br />" );
	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //
	loop times = trialCount {
		echo( "<br />" );
		// -- TEST ONE --: Calling the createObject() function every time I need to access one
		// of the underlying Java methods.
		timer
			label = "Calling createObject() every time"
			type = "outline"
			{
			loop times = iterations {
				value = createObject( "java", "java.lang.Long" )
					.toString( randRange( 1, 100 ), 36 )
				;
			}
			echo( "Last value: #value#" );
		}
		// -- TEST TWO --: Caching the result of createObject() function, and then reusing
		// the cached class when I need to access one of the underlying Java methods.
		LongClass = createObject( "java", "java.lang.Long" );
		timer
			label = "Reusing Cached Class"
			type = "outline"
			{
			loop times = iterations {
				value = LongClass.toString( randRange( 1, 100 ), 36 );
			}
			echo( "Last value: #value#" );
		}
	}
</cfscript>

Each trial is running 1,000,000 loop iterations for each test. I had to jack this number of pretty high before I started to see any performance difference. And, when we run this ColdFusion code with 1 million iterations, we get the following output:

Testing showing that the average duration of each approach was within about 70ms (over 1 million iterations).

As you can see, there is some performance overhead to calling the createObject() function. However, it is extremely small, showing only about a 70ms aggregate overhead over the course of 1 million invocations. Essentially, there is no difference.

I’m glad I did this because caching the createObject() value adds complexity to my ColdFusion code. And, seeing that there’s no meaningful overhead in calling the createObject() function, I’m going to stop trying to cache these values. Clearly, it was a premature optimization; and, I’m happy to be rid of it.

Want to use code from this post?
Check out the license.

Source: www.bennadel.com