jvm运行时内存
2021-10-12 19:16:34 0 举报
运行模型
作者其他创作
大纲/内容
java类库
栈帧
pc(程序计数器)存放程序执行的下一条指令位置
返回地址(记录该方法入口)
类常量池
这一阶段的任务就是把常量池中的符号引用转换为直接引用,说白了就是jvm会将所有的类或接口名、字段名、方法名转换为具体的内存地址。eg:
jit及时编译器
字符串常量池
jvm
int g = 2147483647(四个字节); 此时ldc #4 <2147483647> 压入四个字节的时候使用常量池引用 ldc index:表示引用常量池引用 在.java编译为.class 文件的时候就确定了 那么没有引用而是直接sipush(压入一个short)或者bipush(压入一个字节)的值来自哪里? 这里 对于long和double而言 long:long h = 123L; 在常量池中连续开辟8个字节的空间存储该值 之所以划分是局部变量表中一个槽只能存储4个字节 打开局部变量表的index 8直接到下面name的index=10 所以占用了二个槽位 A value of type long or type double occupies two consecutive local variables
堆内存
栈帧 对应一个方法
这个main方法保存在哪里了,如果是解释执行,new :在堆内存中使用默认值创建一个对象的实例,并将引用压入栈dup:复制该对象的空间首地址值并压栈invokespecial :调用构造方法,为实例成员赋初值线程启动的时候 在栈中创建一个栈帧(包含变量表,操作数栈,动态链接,返回地址)此时的栈帧已经提取出该方法的局部变量存放在局部变量表中
jvm存在一套与当前操作系统对应的指令集 用于解释字节码指令的时候
在类加载之后,new Child()就是创建Child对象,创建对象过程包括: ①:分配内存 ②:对所有实例变量赋默认值 ③:执行实例初始化代码 分配的内存包括本类和所有父类的实例变量,但不包括任何静态变量。实例初始化代码的执行从父类开始,先执行父类的,再执行子类的。但在任何类执行初始化代码之前,所有实例变量都已设置完默认值
一份
heap
lib/rt.jar或者 charset.jar等核心类rt表示runtime的
加载jre/lib/ext/*.jar或者由-Djava.ext.dirs指定加载目录
这里分配的内存包括类和所有父类的实例变量;但不包括任何静态 变量实例初始化代码的执行从父类开始,先执行父类的,再执行 子类的。但在任何类执行初始化代码之前,所有实例变量都已设 置完默认值
字符串和字符类型
app
这个通过Child.class可以找到或者child.getClass也可以找到已加载在方法区的字节码可以通过ASM 使用这一部分aop面向切面编程
执行引擎()
一个类的信息主要包括以下部分: 类变量(静态变量) 类初始化代码 (静态代码块) 类方法(静态方法) 实例变量 实例初始化代码 实例方法 父类信息引用 加载进内存 保存在方法区
基类和子类加载过程和实例化过程
public class AppTest {\tpublic static void main(String[] args){\t\t//\t Dog dog = new Dog(\"旺财\
一个类的信息主要包括以下部分: 类变量(静态变量) 类初始化代码 类方法(静态方法) 实例变量 实例初始化代码 实例方法 父类信息引用 类初始化代码包括: 定义静态变量时的赋值语句 静态初始化代码块 实例初始化代码包括:定义实例变量时的赋值语句 实例初始化代码块 构造方法 类加载过程包括: 分配内存保存类的信息 给类变量赋默认值 加载父类 设置父子关系 执行类初始化代码
custom classloader
Animal.java
寻找要执行的实例方法的时候,是从对象的实际类型信息开始查找的,找不到的时候,再查找父类类型信息
关于new和初始化的区别:当class加载到内存初始化的时候生成字节码对象,以及执行静态语句块和给静态变量赋初始值new方法执行才会有实例的概念
classloader
bootstarp
javac
存放加载进来的.class文件的 常量池,方法,和初始化方法以及方法的数据,filed注意:方法区是heap的一部分,可以是固定大小也可以按需增加
CONSTANT_Utf8_info的作用
主要做的就是为由static修饰的成员变量分配内存,并设置默认的初始值 1.八种基本数据类型默认的初始值是0 2.引用类型默认的初始值是null 3.有static final修饰的会直接赋值,例如:static final int x=10;则默认就是10.(因为不需要变化的)
加载classpath下的
在运行时引擎中运行,运行的时候,内存中情况
方法区(包含运行时常量池)
执行引擎
.java
数字类型
启动jvm通过类加载器
方法等其他内容
动态链接
操作数栈 弹入弹出更改a值
linked
验证
需要说明的是,关于类初始化代码,是先执行父类的,再执行子类的,不过,父类执行时,子类静态变量的值也是有的,是默认值
.class
AppTest
红色区:线程共享
给静态变量赋初始化值()
methodArea
基本数据类型存放位置:①:static int age = 12; //静态属性何时被初始化 以及12存储位置在在哪里?在<Clinit>初始化 在类的初始化 ②:final static int wigth = 15;//静态常量 当类加载进jvm的时候?在类被加载进jvm的时候 解析出final修饰的字段 由于final修饰的不会在变化所以单独存储到内存使用在其他类使用的 时候直接赋值 ③:int heigth =10;//类属性字段 ----》在<init>初始化 实例初始化④:final int wigth = 15; 也是在实例初始化的时候赋值上述四种在当做类属性字段的时候 在运行时数据区
jvm运行时数据区(用户空间)
method area
stack 根据线程开辟的空间
.class文件
方法区类的存储结构
堆
我们知道,在Java中有两种创建字符串对象的方式:①:采用字面值的方式赋值②:采用new关键字新建一个字符串对象。这两种方式在性能和内存占用方面存在着差别。( 通过ldc #2 <huang> #2为引用 );目前的字符串常量池存放在堆中(专门在堆内存区域开辟一个空间存储字符串的区域),当通过String str = \"aaa\"创建的时候 会先检查堆中的字符串常量池存不存在aaa这个对象,如果存在这接返回这个aaa对象的引用地址 到栈帧中的操作数栈顶;对于String str=new String(\"aaa\") ,会调用存在intern方法查看字符串常量池中是否存在aaa如果存在 则在堆中创建String(\"aaa\") +一个引用对象(放在栈中)如果不存在 则在常量池中创建aaa对象以及堆中创建String(\"aaa\")对象 +一个引用对象(放在栈中)引用也算对象String str = new String(\"aaa\")当常量池中存在\"aaa\"对象 则只需要在堆中创建new String(\"aaa\")对象+引用对象(栈中)如果常量池中不存在\"aaa\"对象 需要在常量池中创建\"aaa\"对象+new String(\"aaa\")对象+引用对象String str1 = new String(\"A\"+\"B\") ; 会创建多少个对象?str1:字符串常量池:\"A\
new Student() 的过程发生了什么?堆内存中开辟一个空间 并调用构造方法初始化改对象,然后将引用对象压入栈构造方法干了什么?初始化属性字段 为字段赋默认值属性在什么时候初始化(赋值)?执行构造函数的时候初始化<linit>(实例的初始化)静态属性在什么时候初始化(赋值)?在类加载 链接初始化的时候 链接阶段中的准备阶段赋默认值,在初始化阶段赋初始值以及执行静态代码块 <clinit>(类的初始化)
自定义class loader;想加载那你的就加载那你的 看自己定义
常量池
字符串常量池的应用
准备
misc.launcher类classLoader类
继承的实现 虚拟方法表 子类.method 如果该方法在子类存在则调用子类方法; 如果子类没有找到 则在父类查找是否存在该方法如果使用 多态 那么引用的类型为父类的话 此时引用只能调用父类自己存在中的方法
unloading
硬盘中
Dog.java
在工作中,String类是我们使用频率非常高的一种对象类型。JVM为了提升性能和减少内存开销,避免字符串的重复创建,其维护了一块特殊的内存空间,这就是我们今天要讨论的核心:字符串常量池。字符串常量池由String类私有的维护。
操作系统或者硬件
Child c = new Child();会将新创建的Child对象引用赋给变量c,而Base b = c;会让b也引用这个Child对象。创建和赋值后,内存布局大概如下图所示:引用型变量c和b分配在栈中,它们指向相同的堆中的Child对象,Child对象存储着方法区中Child类型的地址,还有Base中的实例变量a和Child中的实例变量a。创建了对象,接下来,来看方法调用的过程。 方法调用我们先来看c.action();这句代码的执行过程是:①:查看c的对象类型,找到Child类型,在Child类型中找action方法,发现没有,到父类中寻找②:在父类Base中找到了方法action,开始执行action方法③:action先输出了start,然后发现需要调用step()方法,就从Child类型开始寻找step方法④:在Child类型中找到了step()方法,执行Child中的step()方法,执行完后返回action方法⑤:继续执行action方法,输出end这里的即使step()父类中也存在 依然调用子类的step()
绿色区:独立线程
init
public abstract class Animal {\tpublic String name;\tpublic String address;\tpublic String gender=\"male\
加载的类字节码存放在 方法区
using
栈(线程独立)
局部变量表(a 3)
保存类的实例变量+类信息的应用类变量存储在哪里?static修饰加载进内存存储在方法区
https://segmentfault.com/a/1190000009888357:字符串常量池的设计思想:字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化为字符串开辟一个字符串常量池,类似于缓存区创建字符串常量时,首先坚持字符串常量池是否存在该字符串存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中 实现的基础①:实现该优化的基础是因为字符串是不可变的,可以不用担心数据冲突进行共享 也就是每次String str = \
常量池 https://blog.csdn.net/qq_45737068/article/details/107149922
字节码解释器
初始化,给静态赋初始值
运行时常量池
方法区:为类主动使用加载进来的保存该类的.class文件
解析
在类常量池被加载进jvm的时候 ;具备动态性 也就是运行期间也可能会产生常量
此时str在常量池中 链接的解析阶段为str指向物理存储地址
多态的实现
extend
①
1.7将字符串常量池存放在方法区中;1.8:String常量池已经从方法区中的运行时常量池分离到堆中了,那么在堆中的String常量池里存的是String对象还是引用呢?对象
GC
Human girl = new Girl();
虚拟方法表
0 条评论
下一页