Java内存分析详解 (附图)

public class Student {

	int score;
	int age;
	String name;

	Computer computer;

	public void study() {

		System.out.println("studying...");
	}
}


public class Computer { 
        int price; 
        String brand; 
}


public class Test {

	public static void main(String[] args) {

		Student stu = new Student();

		stu.name = "xiaoming";

		stu.age = 10;

		stu.study();

		Computer c = new Computer();
		c.brand = "Hasse";

		System.out.println(c.brand);

		stu.computer = c;
		System.out.println(stu.computer.brand);

//		System.out.println("----------------------------------------");
//
//		c.brand = "Dell";
//
//		System.out.println(c.brand);
//		System.out.println(stu.computer.brand);
//
//		System.out.println(stu.computer.brand == c.brand);

	}
}

在这里插入图片描述

  1. 通过类加载器把Test类的字节码文件加载到栈的方法区内,Test类加载的信息有:①类的代码信息 ②静态方法、静态变量(静态区)③字符串常亮(常量池)④构造方法、普通方法(方法)
  2. 调用main方法,在栈中创建一个栈帧(后进先出),用于执行main方法.调用main方法,在栈中创建一个栈帧(后进先出),用于执行main方法.
  3. 发现Student stu = new Student(); 在方法区内查找有没有Student类的代码信息,没有的话jvm通过类加载器将Student类的.class字节码文件加载到内存中.发现Student stu = new Student(); 在方法区内查找有没有Student类的代码信息,没有的话jvm通过类加载器将Student类的.class字节码文件加载到内存中.
  4. Student stu = new Student(); 方法中有引用变量、局部变量都存放在main方法的栈帧中;Student stu = new Student(); 方法中有引用变量、局部变量都存放在main方法的栈帧中;
  5. Student stu = new Student(); 调用Student类的构造方法,在该线程的栈中创建一个栈帧,构造方法创建出一个实例对象,存放在堆内存中,对象中存放类的实例变量. int score, int age属于基本数据类型,jvm会将其的值初始化为0,String name为引用类型(字符串),jvm会将其默认为null;Student stu = new Student(); 调用Student类的构造方法,在该线程的栈中创建一个栈帧,构造方法创建出一个实例对象,存放在堆内存中,对象中存放类的实例变量. int score, int age属于基本数据类型,jvm会将其的值初始化为0,String name为引用类型(字符串),jvm会将其默认为null;
  6. 之后来到了Computer computer; 这时发现了Computer类,jvm加载该类的字节码文件到方法区中;computer也为引用类型,默认为null; 对象中的study()方法存放着累着study方法的地址,调用该方法时直接去类中找;之后来到了Computer computer; 这时发现了Computer类,jvm加载该类的字节码文件到方法区中;computer也为引用类型,默认为null; 对象中的study()方法存放着累着study方法的地址,调用该方法时直接去类中找;
  7. 实例对象创建完成之后, Student构造方法的栈帧出栈(被jvm垃圾回收机制销毁),返回值(返回一个对象)压入调用该方法的栈帧的操作数栈中.此时该线程的顶栈是主调方法main方法的栈帧.实例对象创建完成之后, Student构造方法的栈帧出栈(被jvm垃圾回收机制销毁),返回值(返回一个对象)压入调用该方法的栈帧的操作数栈中.此时该线程的顶栈是主调方法main方法的栈帧.
  8. 每个实例对象创建完成会生成了一个4字节16进制的内存地址,在栈中的引用变量stu中存放该地址,即栈中的stu变量指向堆内存中的Student实例对象;.每个实例对象创建完成会生成了一个4字节16进制的内存地址,在栈中的引用变量stu中存放该地址,即栈中的stu变量指向堆内存中的Student实例对象;.
  9. stu.name = “xiaoming”; stu通过引用Student实例对象的name属性,在Test类的字符串常量池中创建了"xiaoming"字符串对象;将该对象的地址告诉实例变量name;name通过地址指向常量池的"xiaoming"常量;
  10. stu.age = 10; 栈帧中的stu通过地址找到了对象的age变量,由于age是基本数据类型,因此该实例变量被直接赋值为10; stu.age = 10; 栈帧中的stu通过地址找到了对象的age变量,由于age是基本数据类型,因此该实例变量被直接赋值为10;
  11. 引用变量stu通过地址调用堆内存中对象的study()方法,study()方法又通过地址0x13c5指向方法区中类信息的方法,然后调用该方法;引用变量stu通过地址调用堆内存中对象的study()方法,study()方法又通过地址0x13c5指向方法区中类信息的方法,然后调用该方法;

在这里插入图片描述

  1. Computer c = new Computer();jvm在方法区中查找computer类的代码信息,发现有了,就不再加载;
  2. Computer c = new Computer();在main方法的栈帧中开辟一个局部变量c,该变量为引用类型;
  3. Computer c = new Computer(); 调用Computer的构造方法,在栈帧创建一个栈帧;该构造方法在堆内存中实例化一个对象;
  4. Computer的构造方法出栈,返回刚刚创建的Computer对象的地址到主调方法main方法栈帧中的操作数栈中;构造方法出栈,随机被jvm的gc机制销毁,当前线程的顶栈重新回到main方法的栈帧;(只有虚拟机的顶栈才是有效的)
  5. 之后经过操作数栈的算术运算将地址传递给main方法的局部变量c,c中存放Computer类的对象的地址,指向该对象;
    在这里插入图片描述
  6. c.brand = “Hasse” 引用变量c通过内部存放的地址找到了堆内存中的对象,并指向对象中的实例变量brand,将在Test常量池中创建了"Hasse"字符串对象,并将该对象的地址存到brand内存中;
  7. stu.computer = c; 通过引用变量stu找到了堆内存中的Student对象,指向了该对象的实例变量 computer,此时该变量内存中为系统默认值null; stu.computer = c; 通过引用变量stu找到了堆内存中的Student对象,指向了该对象的实例变量 computer,此时该变量内存中为系统默认值null;
  8. stu.computer = c; 将main方法栈帧中的局部变量c内存中存放的地址赋值给实例变量 computer;此时computer也指向了堆中的Computer对象;stu.computer = c; 将main方法栈帧中的局部变量c内存中存放的地址赋值给实例变量 computer;此时computer也指向了堆中的Computer对象;
  9. c.brand = “Dell”; c引用变量通过地址找到了Computer对象,在字符串常量池中创建了"Dell"对象,将"Dell"对象的地址传给实例变量brand;c.brand = “Dell”; c引用变量通过地址找到了Computer对象,在字符串常量池中创建了"Dell"对象,将"Dell"对象的地址传给实例变量brand;

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值