JAVA基础——JVM之方法区、虚拟机堆、常量池、串池及对String的一些理解

JVM 虚拟机堆和方法区

​ 虚拟机堆和方法区都存在与 JVM 的线程共享区,占有 JVM 内存中的很大一部分

虚拟机堆

​ 堆(Haep),在 Java 中所有通过 new 关键字创建的对象都会使用堆内存,堆是线程共享的,在堆中的对象都需要考虑线程安全问题(只要局部变量不逃逸出方法的作用范围,它就是线程安全的),另外堆还存在垃圾回收机制

​ 垃圾回收机制是回收不再被引用、使用的变量,如果不断产生新的对象且都有人在使用,当对象数量达到一定限度时,就会产生堆内存溢出(OutOfMemoryError),可以通过指令设置堆内存上限

-Xmx10m
//设置堆内存上限为 10M

方法区(Method Area)

​ 方法区和虚拟机堆一样,是线程共享区的一部分,JVM 规范指出,方法区逻辑上是虚拟机堆的一部分,但不强制方法区的位置,它用于存储已被虚拟机加载的类信息、常量池、静态变量、即时编译器编译后的代码等数据

​ 方法区的官方定义如下:

2.5.4. Method Area
The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the “text” segment in an operating system process. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods used in class and instance initialization and interface initialization. The method area is created on virtual machine start-up. Although the method area is logically part of the heap, simple implementations may choose not to either garbage collect or compact it. This specification does not mandate the location of the method area or the policies used to manage compiled code. The method area may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger method area becomes unnecessary. The memory for the method area does not need to be contiguous.

永久代(Permanent Generation)

​ 永久代是 HotSpot 虚拟机对方法区的具体实现,永久代本身也存在于虚拟机堆中,在 JDK 1.7 中,移除永久代的工作就已经开始了,存储在永久代中的数据转移到了虚拟机堆或者 Native Memory 中

元空间(Meta Space)

​ 从 JDK 1.8 开始,HotSpot 虚拟机完全移除了永久代,改为在 Native Memory 中存放这些数据,新的空间被称为元空间

常量池(Constant Pool)

​ 一个类的二进制字节码文件大约分为三部分:类的基本信息、常量池、包含的虚拟机指令

​ 常量池的作用是为虚拟机指令提供“常量符号”,根据“常量符号”,虚拟机指令可以找到常量池中存在的数据,所以常量池就是一张表,虚拟机指令根据这张常量表找到要执行的类型、方法名、参数类型、字面量等信息,存在于 .class 文件中

运行时常量池

​ 当一个类被加载时,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址

扫描二维码关注公众号,回复: 9055832 查看本文章

串池(String Table)

​ 为避免字符串被重复创建,JVM 引入了串池的概念,当一个字符串变成字符串对象时,该字符串会在已经被创建好的串池中查找是否有同名的字符串,如果有,就将已存在的字符串的地址赋给该字符串对象,如果没有就将该字符串放入串池中,从而降低相同值得字符串变量对内存得消耗

​ 实际上,串池得本质是一个 Hash Table,字符串是它的 KEY,每当有字符串变成字符串变量时,就会检查串池中是否存在和该字符串同名得 KEY,另外,String Table 不能扩容,在 JDK 1.6 中存在于常量池中,在 1.8 时存在于堆中

​ javac 会在编译期对字符串变量进行优化,例如:String str = “a” + “b”,JVM 认为,"a"是常量,"b"也是常量,所以变量 str 的值在编译期已经决定了,所以会直接将 str 赋值为 “ab”

#####String.intern()

​ String.intern 方法,可以将通过 new 创建的 String 对象放入串池中,并且返回放入串池中的字符串

直接定义的 String 类型变量和通过 new 创建的 String 对象的区别
String str = "a";

​ 创建 str 对象,在 String Table 中查找"a"字符串,如果有,就将 String Table 中"a"字符串的地址赋给 str,如果没有,就将"a"字符串放入 String Table 中,并把 String Table 中的"a"字符串的地址赋给 str

String str = new String("a");

​ 创建 str 对象,在 String Table 中查找"a"字符串,如果有,在虚拟机堆中复制(创建)一个"a"字符串对象,如果没有,就在 String Table 中放入"a"字符串,再在虚拟机堆中创建一个 String Table 中"a"字符串的复制对象

发布了38 篇原创文章 · 获赞 44 · 访问量 3420

猜你喜欢

转载自blog.csdn.net/scfor333/article/details/103394695