JVM内存模型
2021-05-14 10:36:42 2 举报
JVM内存模型
作者其他创作
大纲/内容
类加载器
局部变量表
类加载器ClassLoader
执行引擎(字节码解析的等效过程)
(伊甸园)Eden
程序计数器(Program Count Register)
验证
加载
幸存1区 to
加载ClassLoad
使用
Class模板对象
Java本地接口(JNI)
Native关键字:是为了调用本地底层代码(C/C++)在类中的方法定义,直接增加Native关键字,否则报错,因为未实现,只是声明,类中的方法不允许只定义,但增加了Native关键字就不会报错
解析
栈帧
虚拟机在接受到new指令时,首先检查指令参数是否能在常量池中定位到类的符号引用,并检查符号引用代表的类是否被加载、解析、初始化,如果没有,则先进行类的加载过程
内存初始化
每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有该引用是为了支持方法调用过程中的动态连接。
getClass
老年代/养老区(重GC)
.java源文件
实例化过程:1、虚拟机接受到new指令时,会在常量池中查找有无该类的符号引用,如果没有,则进行类加载操作2、类加载之后,会在方法区生成一个类模板对象,实例化对象,为对象分配内存空间(指针碰撞/空闲列表分配)3、内存初始化,设置初始化值(int:0,boolean:false)4、更新对象头信息5、程序员赋值,设置的初始值会在这里赋值
连接(Linking)
.class字节码文件
对象2
卸载
分类:应用类(系统类)加载器(system class loader)、扩展类加载器(extensions class loader)、根类加载器(bootstrap class loader)双亲委派机制:从根类->扩展类->应用类查找,安全保障调用的是Jdk中的类,作用:安全沙箱安全机制:主要是在连接阶段,对加载的字节码的格式等进行校验,防止病毒代码,外挂等
栈:主要包含对象引用、实例的方法、8种基本数据类型栈溢出(StackOverFlowError:SOF):指一直往栈中压入栈帧,当栈帧达到栈最大容量就会造成栈溢出,常见的栈溢出:函数递归调用层次过深、局部变量体积太大
大对象直接进入老年代
初始化Init
准备
输出执行结果
运行时常量池
1/3
对象3
对象创建的方式:1、通过new关键字2、使用Class类的newInstance方法(反射机制)3、使用Constructor类newInstance方法(反射机制)4、使用clone方法5、使用反序列化机制
额外的附加信息
程序员赋值
JDK1.8之前叫永久代方法区:包含Statics、final、Class、对象信息、方法、字段
对象1
目的:确保转换后的字节码包含的信息符合当前虚拟机的要求验证的内容:文件格式、元数据、字节码、符号引用
Init()
本地方法栈(Native Method Stack)
字节码输入
栈(Stack)
堆和方法区是线程共享的,其他线程私有
new指令
1、真正意义上执行类中定义的java程序代码2、类变量和其他资源的初始化3、初始化阶段是执行类构造器<clinit>()方法的过程。
(加载、连接、初始化)
包括该对象是谁的实例、如何找到类的元数据信息、Hash码、GC分代年龄等
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转化解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
JVM内存模型(虚拟机内存模型)
方法的返回地址
javac编译
实例化
堆(Heap)
幸存0区 from
对象创建过程
字符串常量池
分配内存时两个概念:指针碰撞:为对象分配内存时,内存是规整的,一边是已使用的,一边是没有使用的,指针在中间交界处,在为新对象分配内存时,将需要的内存大小在空闲的内存中分配相应的即可,指针只需要移动对象分配内存大小后的位置,这就是指针碰撞空闲列表:如果分配对象内存时,内存时不规则的,空闲的内存时零散的,那么就没有办法进行指针碰撞,虚拟机就会维护一个表,记录哪些内存是可用的,分配内存时,找到一块足够的内存分配给新对象实例,并更新记录内存维护表,这就是空闲列表
连接Linking
2/3
操作栈
初始化(<clinit>())
虚拟机需要将分配到的内存空间都初始化为零值(如int值为0,boolean值为false等等)
类加载之后便可以确认内存大小
15
类加载
内存分配
Class对象
调用硬件(如打印机)
静态变量
getClassLoader
虚拟机将常量池中的符号引用替换为直接引用的过程
正式为类变量分配内存空间并设置类变量初始值(默认值),变量所使用的内存都会在方法区中分配此处的类变量指的是被static修饰的变量,不包含实例变量,实例变量在对象实例化阶段分配在堆中。当然,也有特殊情况,比如当变量被final修饰时:public static final String ABC = \"abc\";此时,该字段属性是ConstantValue时,会在准备阶段初始化为指定的值。
更新对象头
1、GC垃圾回收,90%都是在堆中,主要是在伊甸园区,还有其他就是在方法区2、每一次GC清理之后,伊甸园区和幸存区to都是为空3、GC垃圾回收算法:引用计数法,标记-清除算法、复制算法、标记整理算法、分代收集算法4、堆内存调优:堆内存溢出(OOM:OutOfMemory):当堆中一直存储数据,达到最大堆内存容量,就造成了堆内存溢出常见的堆溢出原因:死循环创建对象,字符串一直追加
程序计数器是用来记录了线程正在执行的操作的字节码的行号指示器特点:1、线程隔离性,多线程间互不影响2、执行Java代码时,程序计数器是有值的3、执行Native方法时,程序计数器是为空的4、程序计数器所占内存非常小5、JVM中唯一一个没有规定任何OOM的区域
分类:解释执行(通过解释器执行)和编译器执行(通过即时编译器产生本地代码执行)概述:在不同的虚拟机实现里面,执行引擎在执行Java代码的时候可能会有解释执行(通过解释器执行)和编译器执行(通过即时编译器产生本地代码执行)两种选择,所有的Java虚拟机的执行引擎都是一致的:输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果。
1、通过一个类的全限定名来获取定义此类的二进制字节流2、将该二进制字节流的存储结构转换为方法区运行时的数据结构3、在内存中生成一个代表该类的java.lang.Class对象,作为方法区这个类各种数据的访问入口
动态链接
字面量符号引用
新生代/新生区(轻GC)
方法区/元空间(PermGen)
运行时数据区
0 条评论
下一页