java内存分析、staic内存分析

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();
    }
}

  1. 方法区加载类信息和static变量和static方法,company指向"北京尚学堂"
  2. 栈中创建main栈帧,arg初始值为null
  3. u局部变量初始值为null,运行new User(101,“高小七”),创建User构造方法,该构造方法有三个参数(this为隐藏参数)
  4. this地址指向0x1,id为101,name指向"高小七",u的null改为指向地址0x1
  5. 堆中0x1的地址,地址中的属性和方法根据方法区中类信息。id初始值为0,name初始值为null
  6. 构造方法中,this.id = id,0x1下的id等于构造方法栈帧中的id,0x1下的name指向栈帧中的name,最终指向"北京尚学堂"
  7. 第一行代码运行结束,User构造方法出栈
  8. User.printCompany();直接运行打印
  9. u.login();静态方法只能调用静态变量不能调用非静态变量,但是非静态方法也可以调用静态变量
  10. User.company = “北京阿里”;方法区中company指向"北京阿里
  11. u.printCompany();静态方法不仅可以直接用类名调用,也可以被类的所有实例对象调用
    在这里插入图片描述

Guess you like

Origin blog.csdn.net/qq_45895520/article/details/119244779