JVM之内存结构

JVM主要由三部分组成:类加载器、执行引擎和运行时区域。运行时区域主要分为程序计数器、虚拟机栈和本地方法栈以及堆和栈。其中方法区和堆是线程共享,而虚拟机栈、本地方法栈和程序计数器是线程独占。如图所示:

 

 

 

一 静态常量池、字符串常量池和运行时常量池

1.1 静态常量池

静态常量池位于编译后的字节码文件中,用户存放字面量和符号引号。字面量既包括字符串,比如private String desc = “人”,也包括常量值,比如private static final int year = 2021。而符号引号就是用一组符号来描述引用,比如类和接口的全限定名,字段名称或者方法名称等。比如有两个类,com.ecom.A 和com.ecom.B, 其中A引用了B,在编译A的时候,并不知道B的实际地址,就通过com.ecom.B来表示。

 

1.2 字符串常量池

字符串常量池是方法区或者堆中用来存储字符串常量的池子,可以提升系统性能,如果字符串常量池有则返回该字符串在常量池的地址;否则需要新分配地址给这个字符串。

 

1.3 运行时常量池

在JVM进行类加载的时候,将字节码文件中的静态常量池内容加载到内存中,我们知道静态常量池有字面量和符号引用等,静态常量池中的字面值和符号引号就会放到运行常量池中。

但是,JDK 1.7之后运行时常量池中的字符串常量池移到了堆中;符号引用也移到了本地直接内存中。所以运行常量池在JDK1.7之后,就只包括类、字段、方法、静态变量和方法等静态常量池中的信息。JDK1.8之后,静态变量和静态方法也移到了堆内存中。

二 方法区

方法区:是JVM规范中内存区域的一部分,并不是真正的实现,在具体的实现中JDK1.6以前是永久代(Perm), JDK1.7 以后叫做元数据区(Metaspace)。方法区主要存储JVM加载的类信息(字段,方法,接口等)、静态变量、常量池。

 

注意:

第一:JDK1.7之后方法区中的字符串常量池移到了堆内存中,符号引号移到了直接内存。J

第二: JDK1.8之后将方法区中静态变量也移到了堆中,并且方法区剩余的东西,比如类、字段、方法元数据信息全部移到了元数据空间,而元数据空间则是分配到直接内存上的。

 

为什么移除永久代? 

字符串存在永久代中,容易出现性能问题和内存溢出。 

 

三 虚拟机栈

每一个方法都会在栈上创建一个栈帧的数据结构,来存储局部变量表、操作数栈等。

局部变量表: 是一个数组,用于存储方法参数和方法局部变量,是基于下标来访问的。

操作数栈:存储操作数的数组

public int foo(int a, int b) {
    int c = 100;
    int d = a  + b;
    int r = d * c;
    return r;
}

 

 

 

四 本地方法栈

本地方法栈和虚拟机的栈差不多,只不过虚拟机栈存放的是java方法调用信息,本地方法栈存放的是本地方法调用信息

 

五 程序计数寄存器(Program Count Register)

每一个方法或者线程都有自己独立的程序计数器寄存器,用于记录下一条需要执行的指令的地址。因为在多线程环境下,存在上下文切换到的问题,如果之前的线程没有记录下一条需要执行哪一条指令,下一次CPU切回到这个线程的时候,就不知道下一条指令执行什么。

 

如果当前线程正在执行一个Java方法,则程序计数器记录正在执行的字节码地址;如果当前线程正在执行本地方法,则寄存器为空。因为这不属于JVM的范畴。

 

六 堆

堆也是被所有线程共享的一块内存区域,在虚拟机启动的时候创建,主要存放对象实例。在JDK1.7的时候,运行时常量池中的字符串常量池移到了堆中;JDK1.8静态变量移到了堆中。如图示:

public class Person {
    private String name,gender;
    private int age;
    private double salary;
    private static int numCreated;
    private static String desc = "人";

    public Person(String name, String gender, int age, double salary) {
        this.name = name;
        this.gender = gender;
        this.age = age;
        this.salary = salary;
        numCreated++;
    }

    public void say(String word) {
        System.out.println(word);
    }

    public void introduce() {
        System.out.println(this.name + "在"+this.age+"岁的时候,薪水是"+this.salary+"元");
    }

    public static void show() {
        System.out.println("Person已经创建了"+numCreated+"个实例");
    }
}


public class Test{
    public static void main(String[] args) {
        Person person1 = new Person("叶诗颖","女",30,25000.00);
        Person person2 = new Person("张若尘","男",25,15000.00);
        Person person3 = new Person("楚灵溪","女",20,8500.00);
        person1.introduce();
    }
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫言静好、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值