我有似乎有内存泄漏的 tomcat (Apache Tomcat/6.0.18)。
初步分析
在某一时刻,多台服务器的堆利用率超过了 90%。然后我做了一个堆转储及其分析,指出了两个可能的泄漏:
4 550 个 "char[]" 实例,由 "" 加载,占用 321 358 144 (42,39%) 个字节。
最大实例:
char[5102000] @ 0xd18668c8 \u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000 \u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0204 1,35%) 字节。
由“org.apache.catalina.loader.StandardClassLoader @ 0xbb003c30”加载的“org.apache.tomcat.util.threads.ThreadWithAttributes”的 392 个实例占用 151 940 704 (20,04%) 个字节。
其中 char[5102000] 重复多次并填充为 null。
分析
org.apache.tomcat.util.threads.ThreadWithAttributes
支配树分析表明,罪魁祸首是 CA Wily Introscope。
╔═══════════════════════════════════════════════════════════════════════════════════════╦════════════════════════╦═════════════════╦═════════════════╦═════════════╗
║ Class Name ║ Objects ║ Shallow Heap ║ Retained Heap ║ Percentage ║
╠═══════════════════════════════════════════════════════════════════════════════════════╬════════════════════════╬═════════════════╬═════════════════╬═════════════╣
║ org.apache.tomcat.util.threads.ThreadWithAttributes ║ 392 ║ 53 312 ║ 151 940 704 ║ 20,04% ║
║ #-java.lang.ThreadLocal$ThreadLocalMap$Entry ║ 254 047 ║ 8 129 504 ║ 146 384 296 ║ 19,31% ║
║ ##- com.wily.util.adt.CanonicalObjectPoolWithKey ║ 391 ║ 12 512 ║ 72 506 184 ║ 9,56% ║
║ ##- java.util.HashMap ║ 199 734 ║ 7 989 360 ║ 40 377 784 ║ 5,33% ║
║ ###- com.wily.util.adt.WeakWeakIdentityHashMap ║ 391 ║ 9 384 ║ 11 503 344 ║ 1,52% ║
║ #java.util.HashMap$Entry ║ 207 683 # 4 984 392 ║ 16 396 456 ║ 2,16% ║ ║
║ ####- com.wily.introscope.agent.trace.BlamePointTracer$DataAccumulatorGroup ║ 49 807 ║ 1 593 824 ║ 1 593 824 ║ 0,21% ║
║ ####- com.wily.introscope.agent.trace.servlet.ServletObjectFactory$MethodKey ║ 2 563 ║ 61 512 ║ 62 840 ║ 0,01% ║
║ #####- com.wily.introscope.stat.gatherer.IntegerAverageGatherer ║ 92 ║ 5 152 ║ 10 304 ║ 0,00% ║
║ #####- com.wily.introscope.stat.gatherer.IntervalCounterGatherer ║ 109 ║ 4 360 ║ 4 360 ║ 0,00% ║
║ #####- com.wily.introscope.stat.gatherer.IntegerFluctuatingCounterGatherer ║ 55 ║ 3 080 ║ 3 080 ║ 0,00% ║
║ #####- com.wily.introscope.stat.gatherer.IntegerAggregatingFluctuatingCounterGatherer ║ 54 ║ 3 024 ║ 3 024 ║ 0,00% ║
╚═══════════════════════════════════════════════════════════════════════════════════════╩════════════════════════╩═════════════════╩═════════════════╩═════════════╝
字符[]
支配树分析什么也没显示——唯一的积累点是 char[]。分析“Merge Shortest Paths to GC Roots”直接指向org.apache.tomcat.util.threads.ThreadWithAttributes。
╔══════════════════════════════════════════════════════════════════════════════════════════╦════════════════╦════════════════╦═════════════════════╦════════════════╗
║ Class Name ║ Ref. Objects ║ Shallow Heap ║ Ref. Shallow Heap ║ Retained Heap ║
╠══════════════════════════════════════════════════════════════════════════════════════════╬════════════════╬════════════════╬═════════════════════╬════════════════╣
║ org.apache.tomcat.util.threads.ThreadWithAttributes @ 0xd0b12cb8 TP-Processor203 Thread ║ 1 ║ 136 ║ 10 204 016 ║ 240 216 ║
║ - <Java Local> char[5102000] @ 0xd18668c8 \u0000\u0000... ║ 1 ║ 10 204 016 ║ 10 204 016 ║ 10 204 016 ║
╚══════════════════════════════════════════════════════════════════════════════════════════╩════════════════╩════════════════╩═════════════════════╩════════════════╝
问题
是什么负责创建许多用 null 填充的对象 char[]?如何补救不占用头部空间的问题?