类运行过程的内存分析
Java 虚拟机主要可分为stack、heap、method area三个区域,其中栈主要用来存放基本类型变量,对象引用;堆主要存放类实例;方法区存放静态变量、静态方法、常量池。
1 栈的特点
(1) 栈用来描述方法执行的内存模型。每个方法被调用都会创建一个栈帧(存局部变量、操作数、方法出口);
(2) JVM 为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等);
(3) 栈属于线程私有,不能共享;
(4) 栈的存储特性,FIFO;
(5) 栈是由系统自动分配,速度快;栈是一个连续内存空间;
2 堆的特点
(1) 堆用于存储创建好的对象和数组;
(2) JVM 只有一个堆,被所有线程共享;
(3) 堆不是一个连续的内存空间,分配灵活,速度慢;
3 方法区
(1) JVM 只有一个方法区,被所有线程共享;
(2) 方法区实际上也是堆,用于存储类、常量相关信息;
(3) 堆用来存放程序中永远不变的内容,如类信息、静态变量、静态方法、字符串常量;
4 类运行过程中内存分析
(1) 类实例

package cn.latiny.normal; /** * @author Latiny * @version 1.0 * @description: Human * @date 2019/8/2 11:25 */ public class HumanDemo { public static void main(String[] args) throws Exception { Street street = new Street(); street.setName("中华路"); street.setNumber(10000); Location location = new Location("广东", "佛山", street); Human human = new Human(); human.setName("Latiny"); human.setAge(99); human.setLocation(location); System.out.println(human); } } class Humana { private String name; private int age; private Location location; 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 Location getLocation() { return location; } public void setLocation(Location location) { this.location = location; } @Override public String toString() { return "Human{" + "name='" + name + '\'' + ", age=" + age + ", location=" + location + '}'; } } class Locationa { private String province; private String city; private Street street; public Locationa(String province, String city, Street street){ this.province = province; this.city = city; this.street = street; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public Street getStreet() { return street; } public void setStreet(Street street) { this.street = street; } @Override public String toString() { return "Location{" + "province='" + province + '\'' + ", city='" + city + '\'' + ", street=" + street + '}'; } } class Streeta { String name; int number; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } @Override public String toString() { return "Street{" + "name='" + name + '\'' + ", number=" + number + '}'; } }
(2) 类运行过程分析
1)执行HumanDemo 类的main方法时,系统收到我们发出的指令,启动一个Java虚拟机进程;
2)进程首先从classpath 中找到HumanDemo.class文件(如果没有会进行编译后再去查找),之后读取这个文件中的二进制数据;把HumanDemo 类的类信息存放到运行时数据区的方法区中,同时把静态变量和静态方法、常量("中华路", "广东", "佛山","Latiny")加载到方法区,这一过程称为类的加载过程;
3)Java虚拟机定位到方法区中HumanDemo 类的Main()方法的字节码,开始执行它的指令;
4)在栈中开辟一个main() 方法栈帧,执行第一句代码:
Street street = new Street();
Java 虚拟机创建一个Street 实例,使引用变量street 引用这个实例,看似简单的一句代码,但是JVM底层却做了很多工作,让我们来跟踪一下Java虚拟机,看看它究竟是怎么来执行这个任务的:
① Java 虚拟机根据指令需要创建一个Street 实例,于是就直奔方法区而去,需要先找到Street 类的类型信息,结果一看这会儿的方法区里还没有Street类信息,怎么办?Java虚拟机先加载Street 类,把Street 类的类型信息存放在方法区里。
② Street类找到,下面就开始干活啦。Java虚拟机首先在堆区中创建一个新的Street 实例,这个Street 实例持有着指向方法区的Street 类的类型信息的引用。这里所说的引用,实际上指的是Street 类的类型信息在方法区中的内存地址,有点类似于C语言里的指针,而这个地址呢,就存放了在Street 实例的数据区里。
③ 在Java虚拟机进程中,每个线程都会拥有一个方法调用栈,用来跟踪线程运行中一系列的方法调用过程,栈中的每一个元素就被称为栈帧,每当线程调用一个方法的时候就会向方法栈压入一个新帧。这里的帧用来存储方法的参数、局部变量和运算过程中的临时数据。位于 "=" 前的street 是一个在main()方法中定义的变量,可见,它是一个局部变量,因此它被会添加到了执行main()方法的主线程的Java方法调用栈中。而 "=" 将把这个street变量指向堆区中的Street 实例,也就是说,它持有指向Street实例的引用。
整个执行过程如下:
5) 这两句代码运行的过程如下
street.setName("中华路");
street.setNumber(10000);
name 指向方法区常量池的"中华路"
number赋值为10000
6)这句代码JVM做了非常多的工作,具体如下:
Location location = new Location("广东", "佛山", street);
① 加载Location类到方法区;
② 在堆内存中为Location 创建一个新对象,这个对象有指向方法区Location类的引用;
③ main方法栈帧中添加location 局部变量,并指向步骤二创建的对象(保存堆中的实例地址);
④ 给location 对象成员变量赋值,province指向常量池的"广东",city 指向 "深圳",street 指向前面创建的Street对象;
7)这段代码JVM执行过程与之前类似不再详细描述,具体如下图:
Human human = new Human(); human.setName("Latiny"); human.setAge(99); human.setLocation(location);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?