2021-07-30
Java内存分析
首先,我们需要了解主要的的内存机制
-
栈:
- 存放:局部变量、方法
- 先进后出,自下而上存储
- 方法执行完毕,自动释放空间
-
堆:
- 存放new出来的对象
- 需要垃圾回收器来回收
-
方法区:
- 存放:类的信息(代码)、 static变量、字符串常量等.
(注意:只列举了部分作用)
以下面代码举例进行内存分析
class Person{
String name;
int age;
public void show(){
System.out.println("姓名:" + name + " 年龄:" + age);
}
}
public class TestPerson {
public static void main(String[] args) {
//创建 p1 对象
Person p1 = new Person();
p1.age = 24;
p1.name = "张三";
p1.show();
//创建 p2 对象
Person p2 = new Person();
p2.age = 35;
p2.name = "李四";
p2.show();
}
}
第一步方法区加载类信息,
首先运行 main 方法,在栈中创建一个栈帧,传入 arg 参数,初始值为 null
运行第一行语句,首先运行前半句,p1 属于局部变量,所以在栈中,在 mian 的栈帧内,初始值为 null,
运行第一行语句的后半句,new Person(); 运行了构造方法。所以在栈中创建栈帧,堆中加载 Person 的属性和方法,栈中 p1 的值改为地址
第一句运行结束,Person 构造方法的栈帧出栈
运行第二句和第三句,修改堆中对应的值, p1 指向 0x1, p1.age 即为地址是 0x1 下的 age
运行 p1.show(),运行 show() 方法,在栈中创建show 的栈帧,show() 的参数实际上省略了 this,this 指向本对象的地址 0x1,而System.out.println(“姓名:” + name + " 年龄:" + age); 中 name 和 age 都省略了 this,应是 this.name 和 this.age,所以值就是地址为 0x1下的 age 和 name
运行完show()方法,show 的栈帧出栈
下面接着运行,创建 p2 对象
运行完 show 栈帧出栈,最后main出栈,堆、方法区都回收
2021-08-01
关于static的内存分析
在类中,用 static 声明的成员变量为静态成员变量,也称为类变量。类变量的生命周期和类相同,在整个应用程序执行期间都有效
- 它为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化,
- 对于该类的所有对象来说,static成员变量只有一份。被该类的所有对象共享!!
- 可以使用”对象.类属性”来调用。不过,一般都是用“类名.类属性”
- static变量置于方法区中!
用static声明的方法为静态方法
- 不需要对象,就可以调用(类名.方法名)
- 在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static的成员。
- 静态方法不能以任何方式引用this和super关键字
public class User {
int id;//id
String name;//账户名
String pwd;//密码
static String company = "北京尚学堂";//公司名称
public User(int id, String name) {
this.id = id;
this.name = name;
}
public void login(){
System.out.println("登录:" + name);
System.out.println("公司:" + company);
}
public static void printCompany(){
//login();//调用非静态成员,编译就会报错
System.out.println(company);
}
public static void main(String[] args) {
User u = new User(101,"高小七");
User.printCompany();
u.login();
User.company = "北京阿里";
User.printCompany();
u.login();
u.printCompany();
}
}
- 方法区加载类信息和static变量和static方法,company指向"北京尚学堂"
- 栈中创建main栈帧,arg初始值为null
- u局部变量初始值为null,运行new User(101,“高小七”),创建User构造方法,该构造方法有三个参数(this为隐藏参数)
- this地址指向0x1,id为101,name指向"高小七",u的null改为指向地址0x1
- 堆中0x1的地址,地址中的属性和方法根据方法区中类信息。id初始值为0,name初始值为null
- 构造方法中,this.id = id,0x1下的id等于构造方法栈帧中的id,0x1下的name指向栈帧中的name,最终指向"北京尚学堂"
- 第一行代码运行结束,User构造方法出栈
- User.printCompany();直接运行打印
- u.login();静态方法只能调用静态变量不能调用非静态变量,但是非静态方法也可以调用静态变量
- User.company = “北京阿里”;方法区中company指向"北京阿里
- u.printCompany();静态方法不仅可以直接用类名调用,也可以被类的所有实例对象调用