For one reason or another, java often gets bad press for being inefficient, and it's true that it's often less resource-hungry to write things in a language such as C. But there are many advantages to using java (this javaworld article
mentions some of the most important). However, memory utilisation isn't usually one of them, and although quite old, this article
shows how much of a difference there can be. So how can you start to redress the balance? Well, for one, make sure your developers understand java's use of memory and how certain structures use memory. This presentation
should be required reading for all java developers in my opinion
. This blog entry will talk about shared classes, and how you can use them to recover some of the memory on your machine that has been lost to java applications.
Shared classes can help, and they are available in IBM's Java 5 SDK and
above. As the name suggests it allows you to share classes across
multiple JVM invocations, so you no longer have to have large amounts
of your JVMs' address space duplicated multiple times for system
classes. Yes this is effectively implementing shared libraries for
java, but we're not making much use of it yet.
A typical developer's desktop might have several applications running, for example Notes, Symphony, a copy of
Eclipse for development work, maybe an applications server too. If all of these can use the same JVM then you can reduce the overheads and improve performance. With the
IBM JVM which I'm concentrating on here (Most people use Linux or Windows desktops where an IBM JVM is available) you can set options using
the IBM_JAVA_OPTIONS variable, but some of the proprietory startup
scripts in our applications prevent you from setting this in a way that
takes effect. So in order to share classes properly you have to:
- Point all applications at the same underlying JVM
- Set the JVM options to enable shared classes
- If the application sets it's own JVM options, you may need to find a way to override them to stop it ignoring your shared classes options
The first and third of these will probably plant you in the
'unsupported' category if your apps stop working, but works in many
The second of these is often very simple.:
then run your application with a suitable level of JVM. Caches are
named, by default, the same as the user ID who is running the JVM. The
second pair of examples above lets you override the name and disk
location of the shared classes. The class files will be created in that
directory, and will be given a unique name for the level of JVM you are
running, and the name of the cache (caches can't be shared across
different JVM levels) You can also adjust the cache size (at the point
when it is initially created) by adding -Xscmx64M
(for example) - by default your cache size will be 16Mb. On unix,
/var/cache/java would be a good location for a system-wide shared
cache, or you could store it in your home directory.
AOT compilation is new in IBM's java 6.
Because the caches mentioned in the previous section are persistent on
the disk, new JVM startups, even across reboots, can take advantage of
the contents of the cache. IBM Java 6 SR1 will store pre-compiled
native code in the cache to reduce startup times for new JVMs. This
feature works by default when you are using shared classes although it
can be disabled.
Displaying cache information
Using the example above with a
cache name of 'mycache' you can use the following to show all the
caches on the system, give an overview of the cache, and give detailed
information on the current contents of the cache respectively:
The last two examples show how to be more specific about what is shown if required.
The Sun HotSpot JVM also has shared class
facilities as of Java 5, but it is enabled by default and is not backed
by a file system so doesn't help you across invocations. It only works
with the client VM and serial garbage collector. You can force an abort
if it cannot be enabled using "-Xshare:on" on the command line.
I fired up 3 copies of a small java monitoring
application before and after enabling shared classes. The amount of
memory used by each copy was as follows (The three numbers are the
amount of kb for each instance):
|Shared memory||Private memory
|Without sharing||10160, 10176, 10000||19416, 20940, 19684
|With sharing ||21368, 21540, 21532||17696, 13748, 14232
You can see quite clearly from here that
enabling shared classes has dropped the amount of private memory by a
reasonable amount. A 10Mb increase in shared usage
is offset once the two instances have started up. So you wouldn't see
too much real benefit til the third. But it's still a good reduction in
memory usage, and if you have more JVMs executing on your system, the
benefit will be worthwhile.
Eclipse, and eclipse-based applications
By default, Eclipse will not make optimal use of shared classes due to the custom class loaders. However, many IBM Eclipse-based products include the OSGI plugin adapter in the
com.ibm.cds package which is used to improve shared classes use within Eclipse, and it is enabled using the following on the JVM command line if it has not been enabled by default:
Using that option I was able to increase the total items in the cache from 8% of a 64Mb cache to 32%. Here are the figures:
| ||Shared memory ||Private memory
|Without sharing ||18680, 31284, 31344||83904, 89040, 89540
|With sharing (16Mb)||24356, 37236, 37216||82996, 89380, 89748
|With sharing (64Mb)||37364, 24848, 37520||90740, 85036, 90596
|Sharing+com.ibm.cds||52696, 52988, 40364||74128, 69172, 63904
So there is a significant difference with using the extra parameters
- Those slides are from a presentation that the authors did at OOPSLA 2008. This year it will also be presented at ICSE in May in Vancourver
, at PLDI in June in Dublin
, and the JAOO developers conference during October in Aarhus, Denmark
- For persistent shared classed (the default in java 6) the shared
memory is implemented using a memory mapped file, so won't show up in
the output from 'ipcs'. For java 5, or if you add the 'nonpersistent'
option to your shared classes options, it will use shared memory.