java程序执行过程中内存分析详解
public class Person {
String name;
int age;
public void show ( ) {
System. out. println ( "姓名:" + name+ "年龄:" + age) ;
}
}
public class TestPerson {
public static void main ( String[ ] args) {
Person P1 = new Person ( ) ;
P1 . age= 21 ;
P1 . name= "张三" ;
P1 . show ( ) ;
Person P2 = new Person ( ) ;
P2 . age= 20 ;
P2 . name= "李四" ;
P2 . show ( ) ;
}
}
本文通过讲解程序执行过程中的内存分析进一步加深对于对象和类的理解。首先了解三方面:虚拟机栈、堆、方法区。这三个概念可以在我另一篇文章上查看。
接下来我将会从“public class TestPerson { ”这一行开始讲。
程序运行的第一步必然是从main方法开始的,所以首先在** 虚拟机栈** 中开辟一块区域作为main方法的栈帧(可以理解为一部分空间)。main方法中首先遇到第一个形参,即args,其值自动赋予null (关于不同变量类型系统自动赋值的方法在另一篇博客有总结),
接下来创建P1 对象:“Person P1 = new Person ; ”这句话中,Person P1 是一个引用型变量,四个字节,刚开始其值仍然为null ,接下来“new Person ; ”是创建Person类的一个对象(通过构造方法完成),只要是执行方法, 必然会在** 虚拟
机栈** 中开启一个栈帧,那么也将开辟一个空间。形成的对象将出现在** 堆** 中,那么,对象是怎么了解它应该有哪些属性(本文中是age和name)的呢,其实在main方法开始的时候就已经在** 方法区** 中加载了Person类信息,并且此时创建出来的对象都是赋予默认值的
(name= null ,age= 0 ,应注意show方法对于每一个对象都是通用的,所以并不在** 堆** 中,而是在** 方法区** 中,** 堆** 中的show保存的是方法区中show的地址。当对象建成后,对象的地址(假定是1234 )赋予P1 ,P1 不再是null ,而是1234 。至此,第一行程序执行完毕
(先加载类信息,再开辟栈帧),因此执行构造方法产生的栈帧也将被回收
接下来执行下面的程序:“P1 . age= 21 ; ”指的是在** 堆** 中将age赋值24 ,那么name是直接赋值为张三吗?不是的,因为张三并不是java中的8 种基本数据类型,是一个类,它也是对象,需要我们定义,所以“张三”、“李四”这样的类如同Person类一样,在程序启动的时候,
就已经在方法区(的常量池中)加载完毕了,当然也是类似于show方法通过地址链接。接下来到“ P1 . show ( ) ; ”了,既然show方法也是一个方法,那么** 虚拟机栈** 中就会开辟一块栈帧供其使用(同样,方法运行完后,系统自动回收栈帧)。那么问大家一个问题:P1 . show
有没有参数呢?表面上看起来没有,其实是有的,它有一个隐式参数this ,其值为1234 ,熟悉吗,就是P1 的地址,说到底就是自己调用自己,它的作用很大,就在于解决了show方法调用时该如何使用参数的问题,比如在执行P1 = 时调用age,name就是this . age(通过找地址
1234 对应的参数),就可以做到this . name特指P1 的,而不是对象P2 的。show方法执行完毕后,对应的栈帧会被回收。
好了,创建P1 讲完了,创建P2 留给大家,应注意的是,P2 创建结束后,回收show方法的栈帧后,main方法也执行完了,其栈帧也应该被回收。
! [ 在这里插入图片描述] ( https: / / img- blog. csdnimg. cn/ 20210213143506851. png? x- oss- process= image/ watermark, type_ZmFuZ3poZW5naGVpdGk, shadow_10, text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3R1ZGFuYmFvdGlhbg== , size_16, color_FFFFFF, t_70)