类运行过程的内存分析
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);
原文地址:https://www.cnblogs.com/Latiny/p/11307550.html
- JSP Session管理
- 明年4月1日起扫码付款将限额 最低单日限额500元
- 支付宝、微信支付即将限额?这让出门不带钱包的我怎么过!
- 王者荣耀玩家的福音 区块链技术可以让游戏资产变成真实资产
- 不知道这些的IT人可能白过了2017!
- 什么情况?又出新规定,微信支付和支付宝支付居然要被限额了?
- 三十分钟掌握STL
- 谷歌AI新升级,装备审美功能给照片评分
- 【设计模式】—— 适配器模式Adapter
- 【设计模式】—— 单例模式Singleton
- 【Spring实战】—— 3 使用facotry-method创建单例Bean总结
- JS面向对象高级特性
- 图解闭包
- 【web必知必会】——图解HTTP(上)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 手撸实现UDP和TCP通信
- 3分钟短文 | PHP获取函数参数名,和类定义的常量,都要反射!
- 3分钟短文 | Laravel模型获取最后一条插入记录的ID编号
- 3分钟短文 | Laravel 模型的get find first方法你分清咋用了吗?
- 3分钟短文 ! Laravel拼装SQL子查询的最佳实现
- 对java中的泛型的理解
- 解决elasticsearch集群Unassigned Shards无法reroute的问题
- 一次系统扩容引起的elasticsearch故障及恢复
- WPF SharpDx 性能优化方法
- java中的reference(四): WeakReference的应用--ThreadLocal源码分析
- 聊聊dubbo-go的availableCluster
- 删除排序链表中重复元素的方法
- java异常体系及1.7中的try-with-resources
- JAVA中的静态代理、动态代理以及CGLIB动态代理分析
- 基于centos7 搭建storm1.2.3集群过程