Hi,
We have an application using JRuby (1.7.2 at the moment) which shows
tendencies of memory leaking after running for a long time at a certain
customer of ours. The performance degrades, implying that there is very
little free memory in the Java process (which is also shown by jvisualvm
when we look at it).
The application is a web app, using Mizuno (which is in turn based on
Jetty), Rack, Sinatra and a number of other gems.
Trying to reproduce the problem here today on my local machine, I get
heap usage that looks like this (after 45 minutes of running).
[cid:[email protected]]
Forcing a GC at this point doesn’t seem to reduce the memory footprint
significantly. As can be seen, the graph over “used heap” is steadily
going upwards, which I feel is bad. Am I right about this?
Trying to perform memory profiling (also in jvisualvm) gives me this,
which unfortunately gives very little indication about the real nature
of the problem…
I tried enabling the “Record allocations stack traces” but I don’t know
where to find the output from that. Any ideas?
Any ideas in general about how to attack the problem at hand? Many
thanks in advance…
[cid:[email protected]]
Best regards,
PER LUNDBERG Software Engineer
[email protected]mailto:[email protected]
www.ecraft.comhttp://www.ecraft.com/
tel. +358 (0) 20 759 8687
eCraft Oy Ab, Wolffskavgen 36, FI-65200 Vasa
Most likely problem is something is holding on String instances over
time.
This could be the db driver or your code. It is also obviously possible
it
is JRuby itself, but I think we would get more reports if we were
holding
strings references in a common core class.
A less likely cause of issues where we see lots of byte[] String data
hanging around is because of Copy On Write (COW) String semantics. When
we
dice apart a string all those strings will end up sharing the same data
until something mutates a string. Then it bothers to make a small
right-sized string. This is largely a big win for memory consumption.
OTOH
there is one pathological case…
You read in a huge string (let’s say 2Mb) and you read out a small
substring from it (like a username). That new substring will not
allocate
a new string it will just point into the original string data. So, if
you
then store the username into some long-lived runtime hash you end up
seeing
what appears to be a leak since a 8 char username will really be
pointing
into a 2mb string. fwiw, MRI uses the exact same semantics. I have
only
seen this problem manifest twice in the many years since we implemented
COW
strings but it is a possibility.
Your best bet is to get a heap dump and see what is in all those
byte[]…
-Tom
You might want to try out the Eclipse Memory Analyzer
(Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation and no Eclipse required) to find the
culprits.
Take a heap dump and load it in the analyzer, then try “find immediate
dominators” and “find shortest paths to GC roots” from you byte[]-array
to find who are still keeping them. Be warned though that the analyzer
shows only the Java-classes and you may need to do some additional
digging to find the ruby objects responsible.
See
for
some useful tips.