关于java:java虚拟机运行时数据区域

46次阅读

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

1. 虚拟机外部状况

虚拟机标准定义的运行时数据区域:

jdk1.8 后理论的虚拟机运行时数据区域:

jdk1.8 后的 hotspot 实现的虚拟机运行时数据区域和标准的几个不同点:

  • 将虚拟机栈和本地办法栈合二为一;
  • 元数据区取代办法区,并且不在虚拟机内存中,而是在本地内存中;
  • 运行时常量池由办法区移到了堆中;

2. 虚拟机栈


虚拟机栈为线程公有的区域,由栈帧组成。每执行一个办法都会创立一个栈帧,用于存储局部变量表,操作数栈,动静链接和办法返回地址等信息。每一个办法从被调用到执行实现的过程就是一个栈帧入栈和出栈的过程。如果虚拟机栈的大小固定,那么当申请的栈深度超过虚拟机栈的深度的时候就会抛出 StackOverflowError 异样(常见与递归调用)。如果虚拟机栈能够有限扩大的时候,当扩大时无奈申请到足够的内存时会抛出 OutOfMemoryError 异样。

3. 本地办法栈

本地办法栈和虚拟机栈非常相似,惟一的不同就是虚拟机栈存储的是 java 办法,而本地办法栈存储的是 Native 办法。jdk1.8 后本地办法栈和虚拟机栈曾经合二为一。

4. 程序计数器

线程公有的区域。记录以后线程执行的地址,因为在并发的状况下,每个线程都是片段执行的,因而须要一个区域记录以后线程执行到的地址,不便从新调用的时候可能疾速复原执行。

5. 堆

堆是线程共享的区域。用来存储实例化对象。基本上所有实例化对象和数组都存储在堆上,也是垃圾回收机制作用的次要区域。

6. 办法区

用来存储已被虚拟机加载的类信息,常量,动态变量等数据。办法区又称为“永恒代”因为对于办法区的垃圾回收条件十分刻薄,往往不会进行回收。在 jdk1.8 中去掉了办法区的概念,将其中的运行时常量池移到了堆中,其余局部改为 Metaspace(元数据区)存储在间接内存中。

7. 运行时常量池

用于寄存字面量,符号援用和间接援用。首先看以下的代码:

public class Main{public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "hello";
        String str3 = new String("hello");
        System.out.println(str1 == str2); // true
        System.out.println(str1 == str3); // false
        System.out.println(str2 == str3); // false
    }
}

如果以下面代码中的 str1 和 str2 的创立形式,虚构机会先查看运行时常量池中是否又“hello”对象,显然在 str1 创立的时候是不存在“hello”对象的,因而会在运行时常量池创立一个“hello”对象,当 str2 赋值的时候先查看常量池中是否有,发现有,则不进行创立,而是间接使 str2 指向存在的 str1,因而 str1 == str2 是 true 的。
而 str3 应用 new 关键字创立,则会在堆中先创立一个 str3 对象,此时 str3 是指向堆中的这个对象的而不是指向常量池中。因而 str3 和 str1,str2 比拟都是 false。而创立完对象之后再去查看常量池中是否有“hello”对象,有的话再使堆中的对象指向常量池。如果 new 创立的对象字符串值在运行时常量池中并没有,则不会再在常量池中对变量值进行保护。

public class Main {public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "helloworld";
        String str3 = str1 + "world";
        String str4 = "hello" + "world";
        System.out.println(str2 == str3); // false
        System.out.println(str2 == str4); // true
        System.out.println(str3 == str4); // false
    }
}

这下面的例子,首先 str1 和 str2 显然是指向常量池的两个不同的对象。即当初常量池中有“hello”和“helloworld”两个对象。创立 str3 的时候因为蕴含了 str1,虚拟机无奈判断 str3 是否是常量,因而与 new 办法相似,会在堆中创立一个“helloworld”,并在查看后发现常量池中也有一个“helloworld”,因而再有堆中的对象指向常量池,但记住此时的 str3 指向的仍然是堆中的对象而十分量池,因而 str2==str3 后果是 false。而 str4 是以显式的常量进行创立的,因而在查看过后也是间接指向常量池中的“helloworld”,故 str2==str4 是 true。str3==str4 也是不言而喻了。

正文完
 0