Java程序员从笨鸟到菜鸟(二十七)Java面向对象的内存图图解析

一、代码示例

Car实体类
public class Car {
    private String name; // 车的名称
    private String color; // 车身颜色
    private String type; // 车的类型

    // 空参构造
    public Car() {
    }

    // 含参构造
    public Car(String name, String color, String type) {
        this.name = name;
        this.color = color;
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", type='" + type + '\'' +
                '}';
    }
}
ClassDemo测试类
public class ClassDemo {
    public static void main(String[] args) {
        // 使用空参构造
        Car car = new Car();
        car.setName("兰博基尼");
        car.setColor("橙色");
        car.setType("跑车");
    }
}

二、堆内存、栈内存、方法区的示意图

这里写图片描述

三、程序执行过程分析

  1. 运行一个class文件,使用类加载器,将类ClassDemo加载到方法区,main方法压栈(入栈);
  2. 在栈中执行main方法,当JVM看到Car时,会自动把Car类加载到方法区;当看到局部变量car时会在栈中开辟一块空间,当看到new Car()时,会在堆内存中开辟空间,并将堆内存中的对应地址0x222赋值给car,还会拿到方法区的地址值指向方法区;
  3. 在main方法中运行到car.setName()方法,并不是car在调用setName()方法,而是car根据对象给出的地址值,去堆内存中找相应的对象,再用对象去方法区找到setName()方法,然后将setName()方法入栈,根据地址值给堆内存中的变量赋值,调用完毕setName()方法会出栈
  4. main方法运行结束后会出栈

四、内存模型

多任务和高并发是衡量一台计算机的能力的重要指标之一,一般衡量一个服务器性能的好坏,使用每秒事务处理数(Transaction Pre Second,TPS),代表一秒内服务器平均响应的请求书,而TPS和程序的并发能力有着非常密切的联系
Java内存模型中规定了所有的变量都存储在主内存中,每条线程有自己的工作内存线程的工作内存中保存了该线程使用到的变量到主内存副本拷贝,线程对变量的所有操作(读取、赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量,不同线程之间无法直接访问对方工作内存中的变量,线程间变量值的传递均需要在主内存来完成
8种操作实现工作内存同步到主内存
  • lock(锁定):作用于主内存的变量,把一个变量标识为一条线程独占状态
  • unlock(解锁):作用于主内存变量,把一个处于锁定状态的变量释放出来,释放之后才能被其它线程锁定
  • read(读取):作用于主内存变量,把一个变量从主内存传输到线程的工作内存中,以便随后的load使用
  • laod(载入):作用于工作内存变量,它把read操作从主内存中德奥的变量值放入工作内存的变量副本中
  • use(使用):作用于工作内存的变量,把工作内存的一个变量值传递给执行引擎,每当虚拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作
  • assign(赋值):作用于工作内存变量,它把一个从执行引擎接收到的值赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作
  • store(存储):作用于工作内存的变量,把工作内存的一个变量的值传到主内存中,以便随后的write的操作
  • write(写入):作用于主内存的变量,它把store操作从工作内存中的一个变量的值传送到主内存的变量中

如果需要把一个变量从主内存复制到工作内存,就需要按顺序寻址执行read和load操作,如果把变量从工作内存同步回主内存中,就要按顺序寻址store和write操作,java内存模型只要求上述操作必须按顺序执行,而没有保证必须连续执行

8种基本操作必须满足如下规则

  • 不允许read和load、store和write操作之一单独出现
  • 不允许一个线程丢弃它的最近assign的操作,变量在工作内存中改变了之后必须同步到主内存中
  • 不允许一个线程无原因的把数据从工作内存同步回主内存
  • 一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load和assign)的变量,就是对一个变量进行use或store时,必须是先经过日read和load操作
  • 一个变量在同一时刻只允许一条线程对其进行lock操作,lock和unlock必须成对出现
  • 如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前需要重新执行load或assign操作初始化变量的值
  • 如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量
  • 对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)。

猜你喜欢

转载自blog.csdn.net/u013090299/article/details/80649732