• 【Java】内存分析


    栈的特点如下:

      1. 栈描述的是方法执行的内存模型。每个方法被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)

      2. JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)

      3. 栈属于线程私有,不能实现线程间的共享!

      4. 栈的存储特性是“先进后出,后进先出”

      5. 栈是由系统自动分配,速度快!栈是一个连续的内存空间!

    堆的特点如下:

      1. 堆用于存储创建好的对象和数组(数组也是对象)

      2. JVM只有一个堆,被所有线程共享

      3. 堆是一个不连续的内存空间,分配灵活,速度慢!

    方法区(又叫静态区)特点如下:

      1. JVM只有一个方法区,被所有线程共享!

      2. 方法区实际也是堆,只是用于存储类、常量相关的信息!

      3. 用来存放程序中永远是不变或唯一的内容。(类信息【Class对象】、静态变量、字符串常量等)

    来源:速学堂 4.4 面向对象的内存分析

    了解栈、堆和方法区的特点后,我们来对以下代码进行内存分析

    public class Student {
        //属性(成员变量) field s
        int id;
        String name;
        int age;
        
        Computer comp;
        
        //方法
        void study(){
            System.out.println("我在学习");
        }
        void play() {
            System.out.println("我在玩碧蓝航线!用笔记本"+comp.brand);
        }
        
        Student (){
            //构造方法。用于创建这个类的对象,无参的构造方法可以由系统自动生成
        }
        
        public static void main(String[] args) {
            Student stu = new Student();//通过Student类的构造函数Student()方法新建一个stu对象
            stu.age=19;
            stu.id=19;
            stu.name="水音";
            
            Computer c1 = new Computer();
            c1.brand = "神舟";
            stu.comp = c1;
            
            stu.play();
            stu.study();
        }
        
    }
    
    class Computer{
        String brand;
    }

    让我们回到万物的起点

    javac Student.java 和 java Student

    javac 是将 .java 文件编译成 JVM(java虚拟机)能够读懂的 .class java字节码文件

    java 则是执行字节码文件,我们从这里开始分析

     在调用 java 的时候,启动虚拟机,内存空间如下图所示

    接着是执行 Student 类,执行这个类之前需要找到这个类,首先需要把 Student 类加载到内存空间里面

    接着在方法区里面,就有了这个类的信息

    有了这些信息后,相当于 java Student 这条命令执行完了

    接着就开始寻找 main 方法,main 方法是程序执行的入口

    在调用 main 方法的时候就会在栈中开辟一个栈帧

    main 方法

    public static void main(String[] args) {
            Student stu = new Student();//通过Student类的构造函数Student()方法新建一个stu对象
            stu.age=19;
            stu.id=19;
            stu.name="水音";
            
            Computer c1 = new Computer();
            c1.brand = "神舟";
            stu.comp = c1;
            
            stu.play();
            stu.study();
        }

    main 方法首先定义了一个 Student 类型的引用变量 stu ,目前它的值为空(null

    接着 new 了一个对象,根据 Student 类的构造器(构造方法)新建,因为调用了方法,所以在栈中开辟一个新的栈帧

    开辟完后开始执行这个方法,依据构造器初始化这个类,生成这个类的对象

    执行完后获得对象 ,栈帧弹出

    注意:这里新建好的对象里面所有属性的值均为默认值

    接着将这个新建好的对象给 stu 

    也就是把 stu 的地址指向新建好的对象的地址 

    通过地址值将它们关联起来

    Tip:不用在意 1e6d1014 这个地址是怎么来的,只是随便打的

     接着执行 stu.age 

        public static void main(String[] args) {
            Student stu = new Student();//通过Student类的构造函数Student()方法新建一个stu对象
            stu.age=19;
            stu.id=19;
            stu.name="水音";
            
            Computer c1 = new Computer();
            c1.brand = "神舟";
            stu.comp = c1;
            
            stu.play();
            stu.study();
        }

    mian 方法里执行,所以在 main 方法的栈帧里面找 stu 对象,根据 stu 的地址找到 age

    并将 age 赋值为 19 

    id 的赋值同上

    需要注意的是 name 的赋值

    找到 name 以后,会在方法区里找到 水音 这个字符串常量并将 name 的地址指向它

    https://www.cnblogs.com/syxy/p/9747953.html

    接着到了 Computer c1 

    public static void main(String[] args) {
            Student stu = new Student();//通过Student类的构造函数Student()方法新建一个stu对象
            stu.age=19;
            stu.id=19;
            stu.name="水音";
            
            Computer c1 = new Computer();
            c1.brand = "神舟";
            stu.comp = c1;
            
            stu.play();
            stu.study();
        }

    main 新建一个 Computer 类型的局部变量 c1,目前它的值也为 null 

    接着执行 new Computer();  调用 Computer 类的构造方法新建一个对象

    class Computer{
        String brand;
    }

    由于没有定义构造方法,所以将按系统按自动生成的默认构造方法来初始化 Computer 

    因为调用了方法,所以要在栈中开辟一个新的栈帧

    和前面一样,

    开辟完后开始执行这个方法,依据构造器初始化这个类,生成这个类的对象

    执行完后获得对象 ,栈帧弹出

    再提一遍

    注意:这里新建好的对象里面所有属性的值均为默认值

     

    接着将这个新建好的对象给 c1 

    也就是把 c1 的地址指向新建好的对象的地址 

    通过地址值将它们关联起来

     接着执行 c1.brand

        public static void main(String[] args) {
            Student stu = new Student();//通过Student类的构造函数Student()方法新建一个stu对象
            stu.age=19;
            stu.id=19;
            stu.name="水音";
            
            Computer c1 = new Computer();
            c1.brand = "神舟";
            stu.comp = c1;
            
            stu.play();
            stu.study();
        }

    在 mian 方法里执行,所以在 main 方法的栈帧里面找 c1 对象,根据 c1 的地址找到 brand

    找到 brand 以后,会在方法区里找到 神舟 这个字符串常量并将 brand 的地址指向它

    接着执行 stu.comp,在 stu 中找到 comp 

    c1 赋值给 comp ,就是将 comp 的地址指向 c1

    相当于 comp 也是指向 614ddd49 

    接着执行 stu.play ,在 stu  中找到 play 方法

    play 方法在栈中创建一个栈帧

    public class Student {
        //属性(成员变量) field s
        int id;
        String name;
        int age;
        
        Computer comp;
        
        //方法
        void study(){
            System.out.println("我在学习");
        }
        void play() {
            System.out.println("我在玩碧蓝航线!用笔记本"+comp.brand);
        }
        
        Student (){
            //构造方法。用于创建这个类的对象,无参的构造方法可以由系统自动生成
        }
        
        public static void main(String[] args) {
            Student stu = new Student();//通过Student类的构造函数Student()方法新建一个stu对象
            stu.age=19;
            stu.id=19;
            stu.name="水音";
            
            Computer c1 = new Computer();
            System.out.println(c1);
            c1.brand = "神舟";
            stu.comp = c1;
            
            stu.play();
            stu.study();
        }
        
    }

    其他的由于也没讲到,所以就不写下去了,仅为学面向对象抛砖引玉之用

    如有错误,多谢指正

  • 相关阅读:
    VUE课程参考---14、v-for中key属性使用
    完全卸载oracle11g步骤
    DBCP连接池配置参数说明
    Linux下通过JDBC连接Oracle,SqlServer和PostgreSQL
    java 数据库连接池 Oracle版
    一个非常标准的Java连接Oracle数据库的示例代码
    软件开发文档范例
    备份spfile 中的一个误区
    oracle备份恢复之rman恢复到异机
    Oracle数据库文件恢复与备份思路
  • 原文地址:https://www.cnblogs.com/syxy/p/9747953.html
Copyright © 2020-2023  润新知