方法区和栈、堆的关系
java栈保存的对象变量指向堆空间中的对象实例,对象实例有一个指针指向方法区中对象的类型
方法区的理解
在《Java虚拟机规范》中说明,“尽管方法在逻辑上属于堆的一部分,但一些简单的实现可能不会选择去垃圾回收或进行压缩”。对呀HotSpot来说,方法区还有一个别名(Not-Heap 非堆),就是为了和堆区分开来
所以方法区是一块独立于堆的内存空间。在物理上可以不是连续的。
方法区的大小也可以设置为固定大小或者可扩展
方法区是一个概念,每家虚拟机的实现也不一样,在HotSpot中具体的落地实现有JDK7中的永久代,JDK8中的元空间。永久代使用的还是虚拟机的内存,而元空间使用的是物理内存。元空间比永久代更不容易OOM异常
如果加载的类太多,导致方法区溢出,也会出现内存溢出错误。因为HotSpot中JDK7和JDK8对于方法区的实现不一样,所以在JDK7和JDK8中抛出的异常有一点差别。在JDK7中抛出的是java.lang.OutOfMemoryError:PermGen space。在JDK8中抛出的是java.lang.OutOfMemoryError:Metaspace
关闭JVM方法区也被释放
设置方法区内存大小
元空间可以使用以下两个参数设置大小
-XX:MetaspaceSize=50M:设置初始元空间大小为50M,默认的大小是21M。
-XX:MaxMetaspaceSize=100M:设置最大的元空间大小,默认是-1(及不限制)
与永久代不同,元空间是有可能耗净物理内存的。如果元空间溢出一样会抛出OOM异常
如果方法区内存达到了MetaspaceSize设置的大小(也及高水位线),那么将触发一次Full GC卸载没用的类,然后这个高水位线将重置,新的高水位线取决于Full GC释放了多少元空间,如果释放的过多,那么将适当降低高水位线,如果释放的空间不足,在不超过MaxMetaspaceSize时,适当的提高该值。
如果高水位线设置的过低,那么会导致频繁触发Full GC调高高水位线。