Reputation: 1554
I have a Grails app that is primarily used as a WebService. It provides a very customized type of caching where it stores objects in concurrent hashmap for a number of seconds and potentially combines like messages before they can be processed by another thread. After several months of running without issue, PermGen space eventually reaches its max and I need to restart the server to prevent an OOMError Exception.
I don't think my issue is related to leaking Classloaders, which seems to be the cause of most PermGen issues. I am not ever redeploying this app. PermGen is filling up just from normal use.
I have a feeling my issue may be due to the large number of unique strings my app is handling. My app is making heavy use of GStrings for both logging and for processing before storing in the hashmap, like so:
mOrig.msg += mNew.msg
log.debug("Sending combined message: ${mOrig.msg}")
My question is whether GStrings or Hashmap Entries use String.intern(). If so, I think that would explain why my PermGen Space is filling up. If this is indeed the case, what is the best way to handle this? I have already increased the amount of PermGen space in JVM args. However, it just prolongs the inevitable.
I used the Eclipse Memory Analyzer to compare heap dumps after a month of usage. While this doesn't tell me much about PermGen usage, it was clear that the largest difference between the two heaps are the number of Strings and Hashmap Entries.
Class Name | Objects | Shallow Heap
--------------------------------------------------------------------------
| |
char[] | +1,731 | +268,984
byte[] | +35 | +142,240
java.util.HashMap$Entry | +1,684 | +80,832
java.lang.String | +1,675 | +67,000
org.apache.tomcat.util.buf.ByteChunk | +202 | +12,928
org.apache.tomcat.util.buf.MessageBytes | +146 | +11,680
org.apache.tomcat.util.buf.CharChunk | +162 | +9,072
java.lang.Object[] | -31 | +7,840
java.text.DecimalFormat | +32 | +6,912
int[] | +87 | +6,824
java.lang.String[] | +68 | +5,872
Does anyone have an idea what might be going on here and how to address it? I would like to avoid having to restart Tomcat every few weeks/months.
Thanks!
UPDATE: Adding output from jmap -permstat
. Does anyone know how to read this?
29045 intern Strings occupying 4025008 bytes.
class_loader classes bytes parent_loader alive? type
<bootstrap> 2221 12948256 null live <internal>
0x00002aaac0c40048 1 1952 0x00002aaabe2108a8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac0c3c388 10 211456 0x00002aaac04f0cc8 dead org/codehaus/groovy/runtime/callsite/CallSiteClassLoader@0x00002aaaaf4cf338
0x00002aaac1a2c698 1 3112 0x00002aaabe2108a8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac0159380 1 3128 0x00002aaac04f0cc8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac0158a28 1 3096 0x00002aaac04f0cc8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1dfa188 1 3248 0x00002aaac04f0cc8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1a2f910 1 1952 0x00002aaabe2108a8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac0c6e390 12 239656 null dead org/codehaus/groovy/runtime/callsite/CallSiteClassLoader@0x00002aaaaf4cf338
0x00002aaac1df0a68 1 3200 0x00002aaac0afd9b8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1a2db68 1 3112 0x00002aaabe2108a8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1a36f58 1 3112 0x00002aaabe2108a8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1df9688 1 1952 null dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac0171e70 1 1968 0x00002aaac04f0cc8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1979200 1 1952 null dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac01712a8 1 1952 0x00002aaac04f0cc8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1dec140 1 3096 0x00002aaac04f0cc8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac197ad80 1 1952 null dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1df13e8 1 3120 null dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1a2f1a0 1 1952 0x00002aaabe2108a8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac197c380 1 1952 null dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac0c451c0 1 1952 0x00002aaabe2108a8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaabe2183b8 4 14192 null dead javax/management/remote/rmi/NoCallStackClassLoader@0x00002aaaae81ef70
0x00002aaabfd24688 1 1952 0x00002aaac04f0cc8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaabecd6250 2 19984 0x00002aaabe2108a8 dead org/apache/catalina/loader/WebappClassLoader@0x00002aaaaee35f48
0x00002aaabe217da0 94 900176 0x00002aaabe210930 dead sun/misc/Launcher$AppClassLoader@0x00002aaaae446690
0x00002aaac0170f68 1 1952 0x00002aaac04f0cc8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac0c43bc0 1 1952 0x00002aaabe2108a8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac0c45d60 1 3112 0x00002aaabe2108a8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1df0e68 1 1968 null dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac01716b8 1 1952 0x00002aaac04f0cc8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1a35c58 1 3112 0x00002aaabe2108a8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac0c462e0 1 1952 0x00002aaabe2108a8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac0c87750 1 1968 null dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1a2e4b0 1 3112 0x00002aaabe2108a8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaabfd246f0 1 3128 0x00002aaac04f0cc8 dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1de9830 1 3136 null dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac1982680 1 3120 null dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
0x00002aaac0171a60 1 3112 null dead sun/reflect/DelegatingClassLoader@0x00002aaaae276b20
Upvotes: 2
Views: 536
Reputation: 1530
No, Groovy doesn't intern strings (be it with GString or anything else). I would suggest you use jmap -permstat
to get some information about what eats your PermGen.
Upvotes: 1