|
|
|
Back to newsletter 174 contents
In Java 8, Permgen disappeared, but Metaspace appeared. The interned strings that used to be in Permgen have already moved to the main heap in earlier Java7 versions, and Metaspace in Java8 now contains the class data (class METAdata, hence METAspace) that used to be in Permgen prior to Java8, so is this just a renaming? In terms of contents, yes pretty much, but in terms of memory management, no, this is a fundamental restructing of the space holding class metadata (class fields, method bytecodes, JIT optimisations, etc).
Before discussing Metaspace, let's first quickly run through the basics of Permgen. Permgen was a specific part of the overall Java heap space with it's own parameters. It could get automatically resized up to the -XX:MaxPermSize parameter (defaulted to 64MB). If you interned a lot of strings, or had custom classloaders or many dynamically generated classes, you could get an out-of-memory-error from Permgen - this tended to happen mostly where classes could be dynamically reloaded, or with servlet containers or reflection based applications which dynamically generate many classes. The quick fix was just to increase the MaxPermSize, you rarely bothered tuning to reduce class generation. But if you had a leak in class generation (classloader leaks), it was challenging to identify the cause.
Metaspace has some of the same challenges - identifying classloader leaks will still be equally challenging. But instead of having a default maximum size as Permgen had, Metaspace is unlimited by default. This is achieved by moving from a Java heap memory structure to a more C-like memory management, with memory chunks dynamically allocated from the OS and free lists to manage that memory (the chunks are subdivided into blocks, each holding a unit of metadata, hence if all blocks of metadata in a chunk are no longer needed, it is 'free' and the free list gets updated to make that chunk available). You might ask why was this done only for metadata and not objects too - and the answer is that you wouldn't benefit generally from doing this for Java objects as heap memory management is more efficient; but metadata structures change less often so for them a slower memory management in exchange for more dynamic total memory availability is a reasonable tradeoff.
There are new consequences we need to consider regarding Metaspace. It is unlimited by default so you can end up with huge native memory allocation; mainly that only would happen if you have a classloader leak though. But previously the JVM OS size was bounded (permgen space filled and you got an OOME), now you can fill OS memory if you have a classloader leak (NOT a normal object leak, those are still bounded by the Java heap). If you need to limit the OS memory size of your process you can limit Metaspace size with the -XX:MaxMetaspaceSize flag. Metaspace is garbage collected, which initially happens when the -XX:MetaspaceSize (default 21MB) is filled, this can then reduce or increase for subsequent GCs, depending on how much free space was available after the GC. There are a bunch of other flags similar to other existing GC flags (defaults in brackets): -XX:MaxMetaspaceExpansion (5MB), -XX:MinMetaspaceExpansion (330k), -XX:MaxMetaspaceFreeRatio (70), -XX:MinMetaspaceFreeRatio (40), -XX:UseLargePagesInMetaspace (false).
Generally this is a simplification for Java, you no longer need to worry about hitting "OutOfMemoryError: PermGen". But you do need to beware that the OS structure of your JVM memory is now subtly different, and if you see it gradually increasing beyond expected sizes, consider whether you have a classloader leak. Now on to all our usual sections: links to tools, articles, news, talks and as ever, all the extracted tips from all of this month's referenced articles.
Java performance tuning related news.
Java performance tuning related tools.
Back to newsletter 174 contents