jvm组成
1. 组成结构
JVM 由类加载器子系统、运行时数据区、执行引擎以及本地方法接口组成
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qjea6mHX-1584060529744)(C:\Users\32302\Desktop\typora\img\微信截图_20200107090828.png)]
2.类加载子系统
经过编译器编译的java文件成为字节码文件,字节码文件需要进入jvm内存就需要类加载器加载,加载进去之后会为他创建Class对象。
编译过程:加载--------->连接(验证+准备+解析)------------>初始化
连接
当类被加载后系统会为之生成一个Class对象,接着就进入了连接阶段,简介阶段
负责把类的二进制文件合并到jre中。类连接又分为三个阶段
1. 验证
验证被加载的类是否有正确的类结构、并且和其他类做协调,确保类不会对虚拟机造成危害
验证包括:文件格式验证、元数据验证、字节码验证、符号引用验证。
文件格式验证:
主要验证字节流是否符合Class文件格式的规范,并且保证能被当前的虚拟机加载处理
元数据验证:
对字节码描述的信息进行语言分析、分析是否符合语言的语法规范
字节码验证:
他是最重要的验证环节,分析数据流和控制确定寓意的合法性、符合逻辑,主要
针元数据验证后对方法体的验证,保证方法体在运行时有危害的出现。
符号引用验证:
2. 准备
静态变量分配内存空间,并设置默认初始值。
3. 解析
将类的二进制数据中的符号引用替换为直接饮用
3. 运行时数据区
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wgmYpzKB-1584060529745)(C:\Users\32302\Desktop\typora\img\微信截图_20200108084837.png)]
jvm在执行java程序的过程中会把管理的内存分为若干区域,不同区域做不同工作。
1. 程序计数器
他是一块较小的额内存空间,用来指示指令执行的位置,他的值默认加一,来指向下一指令。
程序的分支、循环、跳转、异常处理、线程回复等都依赖他
2.堆和栈的区别
职责不同,
由于栈是先进后出的这种数据结构,因此很适方法的调用,方法被执行,争取到线程
执行完毕后pc再回到原来执行的地方。
也可以以用来存储局部变量,例如方法内部的变量,如果存储在堆中,是不是开销大了呢
独享还是共享
栈内存由单个线程掌控,因此占内存存储的变量只能本线程可用,就是现成的私有内存,
这也是为什么我们在其他方法里面为啥不能用本方法变量的原因。
堆内存对于所有线程均开放,所以我们可以到处使用对象。
空间大小
由于栈内存只用来存储本方法的局部属性,因此不需要多大的空间,而
对用来存储不痛的对象,而对象一般大一些,所以堆内存会很大,
栈默认1MB
堆是GC的主要区域
3. 本地方法栈
他和虚拟机栈有相同的地方,
不同的是本地方法栈服务的对象是native方法,
6. 方法区
用于存储类结构信息的地方,包括常量池、静态变量、构造函数等。虽然JVM规范把方法区
描述为堆的一个逻辑部分, 但它却有个别名non-heap(非堆),所以大家不要搞混淆了。
方法区还包含一个运行时常量池。特点:
线程安全
由于方法区存储类型西,可被所有线程共享,因此被设计成线程安全的
方法区的内存大小不比固定
jvm可以根据应用场景对大小进行分配,内存可以不连续,他可以是个堆内存,
方法区可以被gc
当某个类不被使用时候,gc可以将它清除内存。
常量池
运行时常量池,他是方法区的一部分,因此是全局的
内存分配:
java中内存分为静态内存和动态内存
静态内存就是固定内存,例如int类型的数据,
动态内存就是不明确内存大小的内存。
4. 执行引擎
负责执行class文件中包含的字节码指令,
5. 本地方法接口
用来规范方法在那里执行,例如本地方法在本地方法栈中执行,
普通方法在虚拟机栈中执行