JavaLoader and memory usage

67 views
Skip to first unread message

Barnaby Relph

unread,
Oct 4, 2011, 7:16:49 AM10/4/11
to javaloader-dev
Hi All,
We're looking at using JavaLoader for a project but have hit a
snag with memory consumption.
Our project uses POI to generate Word documents and because CF9 uses
earlier versions of POI, we need to separate out our own classes,
hence JavaLoader.

The issue we have is that we need to be using POI's ooxml-
schemas-1.1.jar, which is 14.5MB when zipped. We are able to load all
classes using JavaLoader, but memory usage jumps up by about 60 meg
the moment we do. We can store the loader in app scope to make sure we
only loose 60mb once, but we'd like to avoid loosing the 60 meg at
all.
A quick and dirty test of overwriting all of ColdFusion's clashing
JARs shows we can use the latest POI without the memory overhead. Of
course then downsides are that we've just hacked CF and that
deployment becomes harder.
I've reviewed the JavaLoader code and the memory usage seems to be
caused by the use of
com.compoundtheory.classloader.NetworkClassLoader, which caches jar
contents in memory, rather than read-on-demand, which is what the
URLClassLoader appears to do, but with the benefit of not locking the
files.
For our application locking files is not a problem, so I guess my
questions are:
1) Is the NetworkClassLoader used for any reason other than avoiding
locks?
2) Could I replace it with an instance of java.net.URLClassLoader (I
know I'd have to re-write a little bit of JavaLoader as
NetworkClassLoader also makes addURL() public, which URLClassLoader
does not)
3) Am I missing something?

Thanks for any replies and thanks Mark for making JavaLoader public in
the first place!

Mark Mandel

unread,
Oct 4, 2011, 8:01:31 AM10/4/11
to javaloa...@googlegroups.com
A couple of things before I go to bed...

1) You should really be sticking JL in the server scope.

2) Have you done any testing to see if using a URLClassLoader actually results in the 60MB not being used up, even after you've started using the .jar? (I'd be surprised if it didn't. It needs to go somewhere after all).

3) Is 60MB that big of a deal that you would spent this much developer time on it? (Return on investment and all that jazz).

Just some random thoughts before I go to sleep.

Mark
--
E: mark....@gmail.com
T: http://www.twitter.com/neurotic
W: www.compoundtheory.com

cf.Objective(ANZ) + Flex - Nov 17, 18 - Melbourne Australia
http://www.cfobjective.com.au

2 Devs from Down Under Podcast

Barnaby Relph

unread,
Oct 4, 2011, 12:52:45 PM10/4/11
to javaloa...@googlegroups.com
Hi Mark,
thanks very much for getting back to me.

1) Agreed, we'd do that for production
2) Yes, we've used VisualVM to confirm that the heap used is about the
same before and after using our POI-based code. The memory used in
servicing a request for the POI-based code is also about the same as
that used for any other page in our app, so I'm fairly confident that
the URLClassLoader is loading classes and resources on demand.
3) Sadly, yes. Our product is run clustered at lots of customer sites,
so the 60Meg is multiplied many times over. If it was in-house, I'd
absolutely just tweak the JVM config and move on with things.

I've extracted the core bits of what JavaLoader does and I now have a
standalone CFM which uses a URLClassLoader to load our code, create a
JavaProxy and
get an instance of our code and run it, so I know it's workable.

Next I plan on looking at whether I can make the classloader
implementation parameterizable within JavaLoader, as I'd like to add
to it if possible.

I'll report back on how well that works out.

Thanks

Barny

Mark Mandel

unread,
Oct 4, 2011, 5:31:59 PM10/4/11
to javaloa...@googlegroups.com
So if it's in the server scope, wouldn't that be one memory hit per machine? Unless you are running on some super low-spec machines, I'm yet to see the issue.

Basically I'm worried about 2 things:

1) URLClassLoaders are parent first, so you can remove some of the benefit of using JavaLoader, and I'd be surprised if you are successfully overwriting CF's classes as you would like (it's probably grabbing what is loaded into CF) (you would need to extend / write your own classloader to solve this)
2) With a URLClassLoader you will need to shut down CF every time you want to update that .jar file. That make deployment hard.

Mark


On Wed, Oct 5, 2011 at 3:52 AM, Barnaby Relph <ba...@barny.org.uk> wrote:
3) Sadly, yes. Our product is run clustered at lots of customer sites,
so the 60Meg is multiplied many times over. If it was in-house, I'd
absolutely just tweak the JVM config and move on with things.



Barnaby Relph

unread,
Oct 4, 2011, 6:02:34 PM10/4/11
to javaloa...@googlegroups.com
Hi Mark, thanks again for the reply. I'd missed the parent-first nature of the Urlclassloader, so thanks for pointing that out. That explains some behaviour I saw earlier today using the Urlclassloader, an error was being thrown by POI which I didn't see through using JavaLoader. 

The reason I'm keen to avoid the hit is that even in server scope, the hit is once per instance of CF and for a number of reasons, there are more than one instance of CF (and our app) running on each server. There's probably a few hundred instances of our software running on customer machines of varying spec, so it's worth putting in a bit of effort into reducing memory footprint at this stage. If I can avoid making customers upgrade ram, then that's a win. 

With regards to locking, we already have updaters which take care of shutting down CF, updating code, jars, settings etc, so although it's a valid concern for me in development, we don't have that problem in production. 

Thanks very much for getting back to me, I think the options at this point are probably to use JavaLoader and take the memory hit or overwrite the CF classes, I'll have a think about the pros and cons of each. I'll put the JavaLoader version through performance test and see if the reduced RAM has much of a knock-on on performance. 

Any other pointers or opinions greatly welcome

Thanks

Barny

Marc Esher

unread,
Oct 4, 2011, 6:12:36 PM10/4/11
to javaloa...@googlegroups.com
I imagine there must be a reason, but I'll throw this out there
anyway: are you *sure* you need the schemas jar?

I'm using the latest POI bits (3.8 beta 4 I believe) for "streaming"
xlsx generation, and all it requires is poi and the poi-ooxml jar,
*not* the schemas jar.

Marc

Barnaby Relph

unread,
Oct 6, 2011, 6:17:44 AM10/6/11
to javaloa...@googlegroups.com
Hi Marc & Mark,
I believe we've now solved this in 2 different ways:

Marc, thanks for the tip, I spoke to the developer who was using POI
and he's done some mild re-factoring and has been able to remove the
dependency on the Schemas jar, which was the bulk of the memory hit
(40meg roughly). Now we just need to do a little testing.

Mark, I took a look about for a child-first classloader and found
quite a number out there. I took the one here:
http://stackoverflow.com/questions/5445511/how-do-i-create-a-parent-last-child-first-classloader-in-java-or-how-to-overri/6424879#6424879
Swapping that in for the NetworkClassLoader (and changing the
construction logic a little) got me the behaviour I was after.

I've made a minor change to JavaLoader to allow making the ClassLoader
it uses a parameter to init(). All I have to do now is supply my own
classloader in a jar in javaloader/lib and specify
classLoaderClass="whatever" when calling init(). I had to modify the
construction code for the ClassLoader a little to cope with the
different ways that NetworkClassLoader and URLClassLoader are
constructed, but it's minor. The only restriction on the new code is
that it only knows how to construct URLClassLoaders or classes that
derive from it, but that seems to be what most Child-First
implementations do.

Here's an example of how I'm now initializing the JavaLoader:

jlArgs=StructNew();
jlArgs.loadPaths = arrJar;
jlArgs.loadColdFusionClassPath=true;
jlArgs.classLoaderClass="com.olmgroup.classloader.YoniChildFirstURLClassLoader";

jl = CreateObject("component","javaloader.JavaLoader").init(argumentCollection=jlArgs);


I'm not sure if the group allows attachments to posts, so I'll try
that in a minute with the updated JavaLoader.

Thanks everyone for your input

Barny

Barnaby Relph

unread,
Oct 6, 2011, 6:50:18 AM10/6/11
to javaloa...@googlegroups.com
Attempting to post the updated JavaLoader.
JavaLoader.cfc

Marc Esher

unread,
Oct 6, 2011, 9:14:20 AM10/6/11
to javaloa...@googlegroups.com, javaloa...@googlegroups.com
Glad to hear you solved it. Nice work

Marc

Sent from my iPad

> <JavaLoader.cfc>

Reply all
Reply to author
Forward
0 new messages