java内存分析

目录

在进行内存分析之前需要知道的三个概念

栈内存

堆内存

方法区

一张图概括

图解1:使用无参构造器实例化一个类,并且不对该对象进行任何后续操作

图解2:使用有参构造器实例化一个类,并且不对该对象进行任何后续操作

图解3:使用有参构造器创建一个对象,并对该对象进行一些后续操作

总结


在进行内存分析之前需要知道的三个概念

栈内存

  • 栈是一种先进后出(或者说是后进先出)的结构,即最先进入栈的元素最后才能被访问
  • 当线程进入一个java方法函数时,就会在当前线程的栈中压入一个栈帧,这个栈帧用来保存当前线程的状态,例如保存一些参数、局部变量、计算的中间过程、一些其他的数据
  • 当退出函数方法时,通过修改栈的指针便可以将栈中的内容销毁

堆内存

  • 首先需要说明的是,通常所说的“堆栈”并不是一个内容,而是两个内容,即“堆”和“栈”
  • 堆存在的唯一目的就是存放对象实例
  • 每一个java应用都唯一对应一个jvm实例,每一个jvm实例都对应一个堆,并且由堆内存被该java应用所有的线程所共享
  • 关于进程和线程的关系,这边可以简单地认为“一个进程可以包含多个线程,而该进程的所有线程共享该进程的资源”,若要深入了解进程和线程,请学习操作系统
  • 当初始化对象、非static类型的成员变量、字符串常量池、所有的对象实例、数组时,都需要在堆上进行内存单元的分配

方法区

  • 方法区存放的是一些在整个程序中永远唯一的元素
  • 例如一个类或者是static关键字定义的静态属性

一张图概括


图解1:使用无参构造器实例化一个类,并且不对该对象进行任何后续操作

现在有如下的代码段:

//class1.java
public class class1 {
    int age;
    String name;

    public static void main(String[] args) {
        class1 c1 = new class1();
    }
}

这个代码段很简单

在class1.java文件中定义了一个名为class1的类,这一个类有两个成员变量一个静态的方法

接下来对这个代码段逐步进行内存分析


图解2:使用有参构造器实例化一个类,并且不对该对象进行任何后续操作

有如下代码段:

//class1.java
public class class1 {
    int age;
    String name;

    public class1(int age, String name) {
        this.age = age;
        this.name = name;
    }
    
    public static void main(String[] args) {
        class1 c1 = new class1(23, "张三");
    }
}

这个代码段实现了如下的操作:

  1. 定义了一个类,名为class1
  2. class1中有两个成员变量,一个有参构造器,一个静态的程序入口(main方法)
  3. 在程序入口方法中,实例化了一个class1类,名为c1,并且调用了有参构造器进行初始化

下面进行内存分析:


图解3:使用有参构造器创建一个对象,并对该对象进行一些后续操作

有如下代码段:

//class1.java
public class class1 {
    int age;
    String name;

    public class1(int age, String name) {
        this.age = age;
        this.name = name;
    }
}

//class2.java
public class class2 {
    public static void main(String[] args) {
        int age = 24;
        String name = "李四";
        class1 c1 = new class1(age, name);
        age = 25;
        name = "王五";
        createObject(c1)
    }

    public static void createObject(class1 c2) {
        c2 = new class1(26, "王五");
    }
}

这个代码段进行了如下的操作

  1. class1.java文件中有一个类,类名为class1,在这个类中有两个成员变量,有一个有参构造器
  2. class2.java文件中有一个类,类型为class2,在这个类中有一个静态的方法,一个程序的入口
  3. 在main函数中,有两个变量,一句使用有参构造器创建对象的语句,两句对变量的重新赋值语句
  4. 在createObject函数中,使用参数传递的方式创建了一个对象

下面进行内存分析:(过程有点长,耐心观看,并不难)

多说两句题外话,如果在上面的图解中难以理解为什么调用createObject函数的效果是创建了一个新的对象而不是在原来的对象上进行修改,则可以运行以下的代码进行验证:

//class1.java
public class class1 {
    int age;
    String name;

    public class1(int age, String name) {
        this.age = age;
        this.name = name;
    }
}

//class2.java
public class class2 {
    public static void main(String[] args) {
        int age = 24;
        String name = "李四";
        class1 c1 = new class1(24, "李四");
        age = 25;
        name = "王五";
        System.out.println(c1);
        System.out.println(createObject(c1));
    }

    public static class1 createObject(class1 c1) {
        c1 = new class1(26, "王五");
        return c1;
    }
}

这边为了证明所有情况下都是一样的效果,形参和实参名都是c1,但是读者应该要很明晰,第一个打印语句中的c1是main函数中创建的c1对象的地址;第二个打印语句中的c1也是main函数中创建的c1对象的地址;在createObject函数的形参中,形参c1获得的是一个对象的地址,这一个地址是传入的实参c1的副本。

当然,通过上面这一段验证的代码也可以发现java在参数传递时,实际上是按值传递的,无论参数类型是值类型还是引用类型,实参传递给形参的都是一个数值(或者是实参地址的副本)。

总结

java内存分析,当然IDE也是内置了内存分析工具的,但是对于初学者而言,还是建议好好地学习一下不依赖分析工具进行内存分析的方法。

虽然如何不依赖分析工具进行内存分析是一段十分晦涩难懂的内容,但是对于初学者来说是十分必要的,多花一些时间好好地梳理梳理内存分析的流程,对更好地了解java以及深入学习java都有莫大的好处(当然对于其他语言也是如此,如何使用语言是十分简单的,但是理解为什么可以如此使用是有一定难度的),建议从最简单的代码入手,亲自进行几次内存分析以此来更好地理解这一块内容。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值