JAVA程序运行时的内存分配

java程序运行时有哪些内存数据区呢?很多人都将内存分为堆和栈,大家最关心的也是这两块内存数据区,但是这种划分比较粗糙,实际上在程序运行时,还有其他数据区。

根据《JAVA虚拟机规范Java SE 8版》的描述,分为以下几个数据区:

  • 程序计数寄存器:它是线程的寄存器,每一个线程有自己的一块程序计数寄存器,它保存了当前线程正在执行的字节码指令的行号。因为多线程是轮流分配CPU时间来实现的,所以在任意时刻只有一个线程运行,保存每个线程当前执行的行号才能正常恢复线程。
  • :每个线程都有自己的栈,栈的生命周期和线程的生命周期是相同的,栈用于存储栈帧,每个方法存储在一个栈帧上。栈帧上保存着一个局部变量表,因为局部变量不管是基本类型的(存放变量值,类型定了大小就定了)还是引用类型的(存放对象指针,大小固定),存放在栈帧上的大小是固定的,所以局部变量表所需的内存在编译期间就固定了,方法运行期间是不会变化的。
  • 栈帧:栈帧分配在栈上,栈帧对应着方法,栈帧随着方法调用而创建,随着方法结束而销毁。
  • :堆是所有线程共享的一块内存空间,虚拟机启动的时候就创建了,堆用来存放类的实例、数组的对象。
  • 方法区:方法区也是在虚拟机启动时创建的,也是各个线程共享的一块内存数据区,方法区存储了每一个类的结构信息,例如:运行时常量池、静态变量、字段、方法数据、构造函数的字节码内容等。
  • 运行时常量池: 运行时常量池是方法区的一部分,他存储一个类运行时候保存的所有常量,这个常量可能是编译期间确定的,也可能是运行时间确定的。

在这里插入图片描述

1. 对象存在哪里?

对象都存放在堆上,这个是没有问题的。

2. 那么变量存放在哪里呢?

变量的存放位置取决于变量是成员变量还是局部变量。

  • 成员变量:成员变量是定义在类中的变量,不是在方法里面的变量。
    假设一个对象o,有个成员变量a,当a是基本类型时候,变量a和a的值都存在方法区中;当这个成员变量a是引用类型时,方法区上只保存a的对象的引用,变量a实例化出来的对象是在堆上开辟另一块空间。

  • 局部变量:方法的形参和方法内定义的变量都是局部变量。局部变量都是保存在栈上,当局部变量b是基本类型时,b的定义和值都是保存在栈上;当局部变量b是引用类型时,b的对象保存在堆上,在栈上只保存对象的引用值。

3. 方法保存在哪里呢?

每当调用一个方法,就在栈顶新建一个栈块,栈块带有方法的状态和所有的局部变量。如果方法中调用另外一个方法,就将被调用的方法放在栈顶,所以栈顶永远是当前正在执行的方法。

4. 静态变量和方法保存在哪里?

静态变量和静态方法是属于类的,并不属于某一个对象。
在类的第一次加载的时候,就会初始化静态变量,byte、short、int、long会初始化为0,float、double会初始化为0.0,boolean初始化为false,char初始化为0,引用类型会初始化为null。

5. 一个栗子
package javademo.base;

public class DemoDog {
    public static void main(String[] args) {
        int age=3;
        String name = "小花";
        doIt(name,age);
    }

    private static void doIt(String name, int age) {
        Dog dog=new Dog(name,age);
        dog.eat();
    }
}
package javademo.base;

public class Dog   {
    private int age;
    private String name;

    public Dog(String name,int age)
    {
        this.name=name;
        this.age=age;
    }
    void eat() {
        System.out.println(String.format("我叫%s,今年%d岁了,我吃骨头", name,age));
    }
}

以上程序的内存分配分析:

在这里插入图片描述
在这里插入图片描述

发布了74 篇原创文章 · 获赞 74 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/chybin500/article/details/97018370