JVM内存分布
堆 heap:
- 堆用于存储创建好的对象和数组(数组也是对象)
- JVM只有一个堆,被所有线程共享
- 堆是一个不连续的内存空间,分配灵活,速度慢
栈 stack:
- 栈描述的是方法执行的内存模型,每个方法被调用都会创建一个栈帧(存储局部变量,操作数,方法出口)
- JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数,局部变量等)
- 栈属于线程私有,不能实现线程间的共享
- 栈由系统自动分配,速度快,栈是一个连续的内存空间
方法区 method area:
- JVM只有一个方法区,被所有线程共享
- 方法区实际也是堆,只用于存储类,常量相关的信息
- 用来存放程序中永远是不变或唯一的内容。(类信息【class对象】,静态变量,字符串常量)
以该程序为例进行内存分析
public class Student {
int id;
String name;
int age;
Computer computer;
pubulic void study() {
System.out.println("使用电脑" + computer.brand);
}
pubulic void play() {
System.out.println("我在玩游戏");
}
public static void main(String[] args) {
Student stu = new Student();
stu.id = 1001;
stu.name = "张三";
stu.age = 18;
Computer c1 = new Computer();
c1.brand = "戴尔";
stu.computer = c1;
stu.play();
stu.study();
}
}
class Computer{
String brand;
}
程序从main函数入口
javac 编译Student.java
java执行Student.java
java执行Student.java时加载Student类到方法区,静态成员,常量池等都在此时加载
main方法先进栈
然后再堆中开辟一片区域给Student实例
然后在栈中压入引用stu,stu是一组四字节的地址(十六进制)地址,指向Student实例
Student stu = new Student();
接着执行赋值代码
stu.id = 1001;
stu.name = "张三";
stu.age = 18;
找到栈中的stu,通过stu找到堆中的Student实例,进行赋值修改
- 对于例如int这样的基本数据类型,直接赋值
- 对于name的赋值,从方法区中的常量池里面找
接下来执行
Computer c1 = new Computer();
c1.brand = "戴尔";
和之前一样,不再赘述
接下来执行
stu.computer = c1;
c1即对Computer实例的引用,将他通过stu对象,将Student实例的computer属性指向了Computer实例,此时如果修改c1.brand的值,stu.computer.brand也会随之变换
结下来执行两个方法
stu.play();
stu.study();
两个方法分别进栈出栈
之后c1、stu、main依次出栈
栈空之后内存自动释放,程序终止