Maybe you have a large code base or interning multiple lines.
Try jmap:
jmap -permstat <pid>
(Note: option permstatnot available on Windows)
Example:
$ jmap -permstat 22982
Attaching to process ID 22982, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 17.0-b16
100691 intern Strings occupying 5641096 bytes.
finding class loader instances ..Finding object size using Printezis bits and skipping over...
done.
computing per loader stat ..done.
please wait.. computing liveness..done.
class_loader classes bytes parent_loader alive? type
<bootstrap> 303 1355992 null live <internal>
0xdd159fe8 9 94104 0xdd153c30 live sun/misc/Launcher$AppClassLoader@0xae7fcfa0
0xdd153c30 0 0 null live sun/misc/Launcher$ExtClassLoader@0xae7b0178
total = 3 312 1450096 N/A alive=3, dead=0 N/A
You can also try dumping the heap into a file and then uploading it to the Eclipse Memory Analyzer , which will provide you with useful information, such as the Suspicious Flow Report and the Dominator tree.
jmap -dump:format=b,file=heap.bin 22982
PermGen -XX:MaxPermSize JVM.