方法区和Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。在JDK1.7中使用永久代实现方法区,JDK1.8中改为使用元空间实现方法区。
JDK1.7中方法区的实现:在JDK1.7中,使用永久代来实现方法区,永久代实际上是使用了堆中的一部分内存,永久代的大小可以通过-XX:PermSize 和 -XX:MaxPermSize设置,比如-XX:PermSize=64m -XX:MaxPermSize=128m;当永久代内存不够时会抛出OutOfMemoryError:PermGen异常。
JDK1.8中方法区的实现:在JDK1.8中,去掉了堆中的永久代,使用元空间(使用本地内存)来实现方法区,可以使用-XX:MetaspaceSize和-XX:MaxMetaspaceSize来设置元空间的大小,比如-XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m,如果没有设置,元空间大小会根据应用程序在运行时的需求进行调整,如果设置过小,会抛出OutOfMemoryError:Metadata space异常。
废弃永久代的原因:一是:移除永久代可以促进HotSpot JVM与JRockit VM的融合,因为JRockit没有永久代;二是:由于永久代内存经常不够用或发生内存泄露,爆出OutOfMemoryError:PermGen异常。
运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中。运行时常量池做为方法区的一部分,内存收到方法区的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError异常。
字符串常量池和String.intern()方法:深入分析String#intern
直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域;在JDK1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。直接内存的容量通过-XX:MaxDirectMemorySize指定,比如-XX:MaxDirectMemorySize=256m;如果不指定,则默认与Java堆最大值(-Xmx)一样。
9、各内存区域常用参数 内存区域 JDK1.7 JDK1.8栈 -Xss比如-Xss128k -Xss比如-Xss128k
堆 -Xms和-Xmx比如-Xms128m -Xmx256m -Xms和-Xmx比如-Xms128m -Xmx256m
TLAB -XX:+/-UseTLAB比如-XX:+UseTLAB -XX:+/-UseTLAB比如-XX:+UseTLAB
新生代 -XX:NewSize、-XX:MaxNewSize、-Xmn、-XX:NewRatio -XX:NewSize、-XX:MaxNewSize、-Xmn、-XX:NewRatio
Eden、Survivor -XX:SurvivorRatio比如-XX:SurvivorRatio=8 -XX:SurvivorRatio比如-XX:SurvivorRatio=8
方法区 -XX:PermSize 和 -XX:MaxPermSize -XX:MetaspaceSize和-XX:MaxMetaspaceSize
字符串常量池 -XX:StringTableSize -XX:StringTableSize
直接内存 -XX:MaxDirectMemorySize -XX:MaxDirectMemorySize
10、从另一个角度看JVM内存