美文网首页彻底掌握JVM
11-方法区的演进以及StringTable的调整

11-方法区的演进以及StringTable的调整

作者: OpenCoder | 来源:发表于2021-08-14 13:29 被阅读0次
image

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

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

方法区主要存放的是『Class』,而堆中主要存放的是『实例化的对象』

  • 方法区(Method Area)与Java堆一样,是各个线程共享的内存区域。

  • 方法区在JVM启动的时候被创建,并且它的实际的物理内存空间中和Java堆区一样都可以是不连续的。

  • 方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。

  • 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误:java.lang.OutofMemoryError:PermGen space 或者java.lang.OutOfMemoryError:Metaspace

  • 加载大量的第三方的jar包

  • Tomcat部署的工程过多(30 -- 50个)

  • 大量动态的生成反射类

  • 关闭JVM就会释放这个区域的内存。

1.HotSpot中方法区的演进

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

JDK 1.8后,元空间存放在堆外内存中。

本质上,方法区和永久代并不等价。仅是对hotspot而言的。《Java虚拟机规范》对如何实现方法区,不做统一要求。例如:BEAJRockit / IBM J9 中不存在永久代的概念。

现在来看,当年使用永久代,不是好的idea。导致Java程序更容易oom(超过-XX:MaxPermsize上限)

image

而到了JDK8,终于完全废弃了永久代的概念,改用与JRockit、J9一样在本地内存中实现的元空间(Metaspace)来代替:

image

元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代最大的区别在于:元空间不在虚拟机设置的内存中,而是使用本地内存。

永久代、元空间二者并不只是名字变了,内部结构也调整了。

根据《Java虚拟机规范》的规定,如果方法区无法满足新的内存分配需求时,将抛出OOM异常。

2.方法区内部结构

《深入理解Java虚拟机》书中对方法区(Method Area)存储内容描述如下:它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等。

image

这里我们重点关注掌握运行时常量池

3.运行时常量池

方法区,内部包含了运行时常量池

image

要弄清楚方法区的运行时常量池,需要理解清楚classFile中的常量池

  • 常量池

    一个有效的字节码文件中除了包含类的版本信息、字段、方法以及接口等描述符信息外,还包含一项信息就是常量池表(Constant Pool Table),包括各种字面量和对类型、域和方法的符号引用

image

常量池、可以看做是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量 等类型。

  • 运行时常量池

    运行时常量池(Runtime Constant Pool)是方法区的一部分。

常量池表(Constant Pool Table)是Class文件的一部分,用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。

运行时常量池,在加载类和接口到虚拟机后,就会创建对应的运行时常量池。

JVM为每个已加载的类型(类或接口)都维护一个常量池。池中的数据项像数组项一样,是通过索引访问的。

运行时常量池中包含多种不同的常量,包括编译期就已经明确的数值字面量,也包括到运行期解析后才能够获得的方法或者字段引用。此时不再是常量池中的符号地址了,这里换为真实地址。

运行时常量池,相对于Class文件常量池的另一重要特征是:具备动态性。

运行时常量池类似于传统编程语言中的符号表(symboltable),但是它所包含的数据却比符号表要更加丰富一些。

当创建类或接口的运行时常量池时,如果构造运行时常量池所需的内存空间超过了方法区所能提供的最大值,则JVM会抛outofMemoryError异常。

4.方法区的演进细节

首先明确:只有Hotspot才有永久代。BEA JRockit、IBM J9等来说,是不存在永久代的概念的。原则上如何实现方法区属于虚拟机实现细节,不受《Java虚拟机规范》管束,并不要求统一。

Hotspot中方法区的变化:

版本 内容
JDK1.6及以前 有永久代,静态变量存储在永久代上
JDK1.7 有永久代,但已经逐步 “去永久代”,字符串常量池,静态变量移除,保存在堆中
JDK1.8 无永久代,类型信息,字段,方法,常量保存在本地内存的元空间,但字符串常量池、静态变量仍然在堆中。

JDK6的时候:

image

JDK7的时候:

image

JDK8的时候,元空间大小只受物理内存影响:

image

5.StringTable

StringTable叫做字符串常量池,用于存放字符串常量,这样当我们使用相同的字符串对象时,就可以直接从StringTable中获取而不用重新创建对象。

StringTable为什么要调整位置

jdk7中将StringTable放到了堆空间中。因为永久代的回收效率很低,在full gc的时候才会触发。而full gc是老年代的空间不足、永久代不足时才会触发。

这就导致stringTable回收效率不高。而我们开发中会有大量的字符串被创建,回收效率低,导致永久代内存不足。放到堆里,能及时回收内存。

关于StringTable的深入讲解、垃圾回收、性能调优以及字符串的特点会结合视频进行讲解发放

String相关的面试题如下:(可以自行思考)

<pre data-tool="mdnice编辑器" style="margin: 10px 0px; padding: 0px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">`String s1 = "a";
String s2 = "b";
String s3 = "a" + "b";
String s4 = s1 + s2;
String s5 = "ab";
String s6 = s4.intern();

// 问
System.out.println(s3 == s4);
System.out.println(s3 == s5);
System.out.println(s3 == s6);

String x2 = new String("c") + new String("d");
String x1 = "cd";
x2.intern();

// 问,如果调换了【最后两行代码】的位置呢,如果是jdk1.6呢
System.out.println(x1 == x2);` </pre>

6.JVM内存相关的几个核心参数

在JVM内存分配中,有几个参数是比较核心的,我们总结归纳在一起:

指令 描述
-Xms Java堆内存的大小
-Xmx Java堆内存的最大大小
-Xmn Java堆内存中的新生代大小,扣除新生代剩下的就是老年代的内存大小
-XX:PermSize 永久代大小
-XX:MaxPermSize 永久代最大大小
-Xss 每个线程的栈内存大小

7.系统启动的参数设置

我们可以在启动某个类或项目的时候进行VM Options参数设置:

比如

image

运行之前测试过的代码,结果跟设置一致:

image

总结

最后我们通过一个详细图对整个JVM的内存结构做一个总结:

image

相关文章

  • 11-方法区的演进以及StringTable的调整

    《Java虚拟机规范》中明确说明:“尽管所有的方法区在逻辑上是属于堆的一部分,但一些简单的实现可能不会选择去进行垃...

  • JVM(StringTable)代码详解

    package stringTable; //StringTable["a" "b" ] hashtable 结构...

  • String及StringTable(二):java中的Stri

    [toc] 1.什么是StringTable 在前面部门已经涉及到了对StringTable的一些基本使用。但是或...

  • 问题精选-JVM

    一、内存模型以及分区,需要详细到每个区放什么 JVM 分为堆区、栈区、方法区、本地方法栈、程序计数器 方法区:主要...

  • 4、Ps基础(工具栏)

    10-笔触大小调整(大括号【】) 一定要在英文输入法状态下调整,同时关闭大小写 11-调整边缘(Alt+Ctrl+...

  • 宇宙的演进11-宇宙有多大

    我们现在能看到的最远的天体,大概在距离我们300亿光年的地方。不过给出这样一个数字,只能让我们知道宇宙大小的下限是...

  • java8新特性

    行为参数化(Lambda 以及方法引用) 简洁灵活代码的演进 让我们先来看下对apple根据重量排序的不同写法 通...

  • 尽在双11-阿里巴巴技术演进与超越 第五章读后感

    最近公司举办了读书会,选择的书籍是《尽在双11-阿里巴巴技术演进与超越》。 分享是按照每个人选一章的形式,我选择了...

  • JVM内存布局

    JVM虚拟机内存结构,以及它们的作用 线程私有:栈区,本地方法栈,pc指针线程共有:方法区,堆区 JAVA的JVM...

  • java基础-面向对象

    面向对象笔记 一、 对象在内存中的存放方法以及被调用过程 class文件首先被加载到方法区中的class文件内容区...

网友评论

    本文标题:11-方法区的演进以及StringTable的调整

    本文链接:https://www.haomeiwen.com/subject/ywtebltx.html