心耘博客 | ZLPRIME-磊落平生志,破浪去乘风 心耘博客 | ZLPRIME-磊落平生志,破浪去乘风
  • 首页
  • 朝花夕拾
    • 光影记录
    • 生活随笔
  • 代码如诗
    • 100 Days of SwiftUI
    • 后端技术
    • 服务器配置
  • 影集
  • 关于我
  • 更多
    • 专题汇总
    • 友情链接
    • 留言板
  • 0
  • 0

Java创建对象时的内存原理

心耘
2 年前

java程序在运行时,需要计算机在内存中为其分配空间。为了提高运行效率,Java对内存区域进行了划分,每一块区域都有其特定的数据处理方式和内存管理方法。其中,Java中内存分配的三大主要空间分别是:栈空间、堆空间和方法区。Java程序在创建对象时,这三大空间的使用情况是如何的呢?

一、数据准备

准备一个实体类People,和测试类TestPeople:

public class People {
    //成员变量
    private String name = "张一";
    private int age = 20;

    //构造方法
    public People() {
    }

    //有参构造方法
    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //Getter and Setter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public class TestPeople {
    public static void main(String[] args) {
        //使用有参构造器创建对象
        People p = new People("张三", 20);
        //使用set方法修改成员变量
        p.setName("张二");
        System.out.println("姓名:" + p.getName() + ",年龄:" + p.getAge());
    }
}

执行TestPeople类,输出结果为:

Java创建对象时的内存原理

二、执行过程

  1. 加载含main方法的类的字节码文件到方法区

main方法是程序的唯一入口,运行程序时包含main方法的类的字节码文件,会优先加载到方法区

Java创建对象时的内存原理
  1. main方法进入栈内存

字节码文件加载进入方法区之后,main方法被JVM自动调用,进入栈空间运行

Java创建对象时的内存原理
  1. 执行main方法中的代码

开始,从上往下执行main方法中的代码,每行从右往左执行

Java创建对象时的内存原理
  1. new关键字实例化对象

首先会执行 new People("张三", 20),new关键字表示要实例化People类,但是此时People类的字节码文件并没有加载到方法区。因此,首先要将People类的字节码文件加载到方法区。在将People类的字节码文件加载到方法区的时候,People类中的方法会被自动分配地址。这个地址会在后面用于找到该方法,并执行方法中的代码。假设People类的setName方法地址是0x1111

Java创建对象时的内存原理
Java创建对象时的内存原理
  1. 在堆空间中为People对象分配空间,并将这块空间的内存地址值赋值给p。

其中,在堆内存中存放People实例对象的内存区域,还会分为若干区域,分别用于存放实例对象的成员变量值或成员方法的引用地址。实例对象的内存区域中,用于存放成员方法的的区域,存放的并不是成员方法的代码,而是成员方法在方法区中的地址。例如,前面说的setName方法的地址值 0x1111。将来如果对象调用成员方法,可以通过这个地址值找到方法区中的成员方法,然后调用到栈内存中执行。

Java创建对象时的内存原理
  1. 执行默认初始化

对象的默认初始化是默认执行的,会早于其它任何初始化。无论是否给成员变量了设置了默认值,默认初始化都会自动先执行一遍。成员变量的默认初始化值,基本数据类型是0,引用数据类型是null

Java创建对象时的内存原理
  1. 显式初始化

如果在定义People类的时候,为成员变量赋了初始化值,则在默认初始化后,还会进行第二次初始化(显示初始化)。如果在定义类的时候,没有对成员变量赋初值,则省略显式初始化。在定义People类的时候,对name和age都赋了初值,因此,这里还要进行显式初始化:

Java创建对象时的内存原理

ps.在显式初始化时,name属性的初始化值是"张一"。其中"张一"这个字符串的数据值,并不是直接保存在对象的内存区域中。对象中保存的实际是,字符串在常量池中的地址。

  1. 构造器初始化

在经过隐式初始化和显式初始化,接下来需要进行构造器初始化。如果使用的是无参构造器,则不再需要进行构造器初始化,但是我们使用了有参构造器,因此就需要进行构造器初始化,即把对象的属性值修改为有参构造器传入的形参值。

Java创建对象时的内存原理

至此,People类实例化对象的初始化就算完成了。new关键字执行的操作结束,并把对象在堆内存中的地址值返回给 p 引用。

  1. 继续执行main方法中的代码

执行完new People后,接着执行的代码是p.setName。通过"对象名."的方式调用对象成员的方式,本质就是通过p的引用地址,找到对象在堆内存中的位置,再接着在堆内存中获取成员变量的值,或成员方法的地址。然后根据成员方法的地址接着去找到成员方法并执行。在本案例中p.setName的执行过程就是:

  • 通过p指向的0x2222找到对象在堆内存中位置
  • 在0x2222中找到,setName的内存地址 0x1111
  • 调用0x1111位置的setName方法进栈内存中执行
Java创建对象时的内存原理
  1. 继续执行main方法

setName方法中的代码执行完成后,setName方法会出栈,并继续执行main方法中的代码:

Java创建对象时的内存原理

至此,Java创建对象并执行对象成员方法的内存调用流程就演示完了。

参考

java 创建对象的内存图解 (通俗易懂)_Cyan_RA9的博客-CSDN博客_java创建对象内存分配图解

Java 内存分配全面浅析_袭烽的博客-CSDN博客_内存分配技术

java
0
摘草莓2
上一篇
Nacos修改服务权重时报errCode: 500
下一篇

评论 (0)

再想想
暂无评论

心耘

73
文章
167
评论
94
喜欢

标签

centos (13) java (22) jenkins (7) linux (12) lombok (1) maven (1) mysql (3) redis (2) rocky linux (3) spring (8) wordpress (5) 发布 (3) 实用技巧 (7) 教程 (6) 服务器配置 (3) 生活 (5) 部署 (2)

聚合文章

生活杂记(一)
家电选购小结-空调
十一带娃心得
通过War包升级Jenkins版本

专题推荐

7

Jenkins合集

12

服务器配置

猜你喜欢

通过War包升级Jenkins版本

通过War包升级Jenkins版本

1 年前
430 0 0
Linux修改系统时区并同步系统时间

Linux修改系统时区并同步系统时间

1 年前
1,116 0 1
Linux中安装并配置Maven

Linux中安装并配置Maven

1 年前
1,005 0 0
在Centos中新建用户

在Centos中新建用户

1 年前
1,079 0 0

简介

海边微风起,等风也等你

留言板

留言板

小伙伴们

2Broear 乙末博客 若志随笔 豆豆 诗意笔记 元のDiary
Copyright © 2017-2025 心耘博客 | ZLPRIME-磊落平生志,破浪去乘风. 皖ICP备17019582号
  • 首页
  • 朝花夕拾
    • 光影记录
    • 生活随笔
  • 代码如诗
    • 100 Days of SwiftUI
    • 后端技术
    • 服务器配置
  • 影集
  • 关于我
  • 更多
    • 专题汇总
    • 友情链接
    • 留言板

搜索

  • java
  • spring

心耘

73
文章
167
评论
94
喜欢