关于java:无为聊聊java中JVM的方法区

3次阅读

共计 2346 个字符,预计需要花费 6 分钟才能阅读完成。

栈、堆、办法区的关系



办法区在哪里?

https://docs.oracle.com/javas…

《Java 虚拟机标准》中明确阐明:“只管所有的办法区在逻辑上是属于堆的一部分,但一些简略的实现可能不会抉择去进行垃圾收集或者进行压缩。”但对于 HotSpotJVM 而言,办法区还有一个别名叫做 Non-Heap(非堆),目标就是要和堆离开。

所以,办法区看作是一块独立于 Java 堆的内存空间。

办法区的了解

从线程共享与否的角度来看

  • 办法区(Method Area)与 Java 堆一样,是各个线程共享的内存区域。
  • 办法区在 JVM 启动的时候被创立,并且它的理论的物理内存空间中和 Java 堆区一样都能够是不间断的。
  • 办法区的大小,跟堆空间一样,能够抉择固定大小或者可扩大。
  • 办法区的大小决定了零碎能够保留多少个类,如果零碎定义了太多的类,导致办法区溢出,虚拟机同样会抛出内存溢出谬误:java.lang.OutOfMemoryError: PermGen space 或者 java.lang.OutOfMemoryError: Metaspace
  • 加载大量的第三方的 jar 包;Tomcat 部署的工程过多(30-50 个);大量动静的生成反射类
  • 敞开 JVM 就会开释这个区域的内存。

    HotSpot 中办法区的演进

    在 jdk7 及以前,习惯上把办法区,称为永恒代。jdk8 开始,应用元空间取代了永恒代。

    实质上,办法区和永恒代并不等价。仅是对 hotspot 而言的。《Java 虚拟机标准》对如何实现办法区,不做对立要求。例如:BEA JRockit/ IBM J9 中不存在永恒代的概念。

当初来看,当年应用永恒代,不是好的 idea。导致 Java 程序更容易 OOM(超过 -XX:MaxPermSize 下限)


而到了 JDK 8,终于齐全废除了永恒代的概念,改用与 JRockit、J9 一样在本地内存中实现的元空间(Metaspace)来代替

元空间的实质和永恒代相似,都是对 JVM 标准中办法区的实现。不过元空间与永恒代最大的区别在于:元空间不在虚拟机设置的内存中,而是应用本地内存。
永恒代、元空间二者并不只是名字变了,内部结构也调整了。
依据《Java 虚拟机标准》的规定,如果办法区无奈满足新的内存调配需要时,将抛出 OOM 异样。

设置办法区的参数

设置办法区内存的大小

办法区的大小不用是固定的,jvm 能够依据利用的须要动静调整。

jdk7 及以前:

通过 -XX:PermSize 来设置永恒代初始调配空间。默认值是 20.75M
-XX:MaxPermSize 来设定永恒代最大可调配空间。32 位机器默认是 64M,64 位机器模式是 82M
当 JVM 加载的类信息容量超过了这个值,会报异样 OutOfMemoryError:PermGen space。

jdk8 及当前:

元数据区大小能够应用参数 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 指定, 代替上述原有的两个参数。

默认值依赖于平台。windows 下,-XX:MetaspaceSize 是 21M,-XX:MaxMetaspaceSize 的值是 -1,即没有限度。

与永恒代不同,如果不指定大小,默认状况下,虚构机会耗尽所有的可用零碎内存。如果元数据区产生溢出,虚拟机一样会抛出异样 OutOfMemoryError: Metaspace
-XX:MetaspaceSize:设置初始的元空间大小。对于一个 64 位的服务器端 JVM 来说,其默认的 -XX:MetaspaceSize 值为 21MB。

这就是初始的高水位线,一旦涉及这个水位线,Full GC 将会被触发并卸载没用的类(即这些类对应的类加载器不再存活),而后这个高水位线将会重置。新的高水位线的值取决于 GC 后开释了多少元空间。如果开释的空间有余,那么在不超过 MaxMetaspaceSize 时,适当进步该值。如果开释空间过多,则适当升高该值。

如果初始化的高水位线设置过低,上述高水位线调整状况会产生很屡次。通过垃圾回收器的日志能够察看到 Full GC 屡次调用。为了防止频繁地 GC,倡议将 -XX:MetaspaceSize 设置为一个绝对较高的值。

办法区都存什么?


《深刻了解 Java 虚拟机》书中对办法区(Method Area)存储内容形容如下:

它用于存储已被虚拟机加载的类型信息、常量、动态变量、即时编译器编译后的代码缓存等。

永恒代与元空间

1. 首先明确:只有 HotSpot 才有永恒代。

BEA JRockit、IBM J9 等来说,是不存在永恒代的概念的。原则上如何实现办法区属于虚拟机实现细节,不受《Java 虚拟机标准》管教,并不要求对立。

  1. HotSpot 中永恒代的变动

jdk1.6 及之前:有永恒代 (permanent generation)

jdk1.7:有永恒代,但曾经逐渐“去永恒代”,字符串常量池、动态变量移除,保留在堆中

jdk1.8 及之后:无永恒代,类型信息、字段、办法、常量保留在本地内存的元空间,但字符串常量池仍在堆



办法区会产生 GC 嘛?

有些人认为办法区(如 HotSpot 虚拟机中的元空间或者永恒代)是没有垃圾收集行为的,其实不然。《Java 虚拟机标准》对办法区的束缚是十分宽松的,提到过能够不要求虚拟机在办法区中实现垃圾收集。事实上也的确有未实现或未能残缺实现办法区类型卸载的收集器存在(如 JDK 11 期间的 ZGC 收集器就不反对类卸载)。

一般来说这个区域的回收成果比拟难令人满意,尤其是类型的卸载,条件相当刻薄。然而这部分区域的回收有时又的确是必要的。以前 Sun 公司的 Bug 列表中,曾呈现过的若干个重大的 Bug 就是因为低版本的 HotSpot 虚拟机对此区域未齐全回收而导致内存透露。

办法区的垃圾收集次要回收两局部内容:常量池中废除的常量和不再应用的类型。

跪求三连

码字不易,还请点个赞和珍藏~

正文完
 0