- JVM架构
- 内存结构
- jvm划分为五个区域
- 堆(Heap)
- 内存最大
- 线程共享
- 存放对象
- GC主要区域//别名GC堆
- 现代收集器基本采用分代收集算法,堆被细化:
- Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续即可。//当堆中没有内存完成实例分配,并且堆无法再扩展时,将会抛出异常:OutOfMemoryError
- 方法区(Method Area)
- 与堆的共性:
- 线程共享
- 内存不连续
- 可拓展
- 可垃圾回收
- 无法拓展将抛出OutOfMemoryError
- 个性:
- 存储的是:
- 已被虚拟机加载的类信息
- 常量
- 静态变量
- 即时编译器编译后的代码等
- 存储的是:
- 方法区内存回收目标:
- 主要是针对常量池的回收
- 对类型的卸载//条件苛刻,但必要
- 与堆的共性:
- 程序计数器(Program Counter Register)
- 占用内存较小
- 线程私有
- 唯一没有OutOfMemoryError的区域
- 作用:
- 当前线程所执行字节码的行号指示器
- 为了线程切换后能够恢复到正确的执行位置,每条线程都需要有一个独立程序计数器(即计数器线程私有)
- Java虚拟机多线程实现:通过线程轮流切换并分配处理器执行时间的方式实现
- 计数器使用模拟
- 线程不同状态,计数器值eg:
- 线程执行Java方法,计数器记录正在执行的虚拟机字节码指令地址
- 线程执行Native方法,计数器为空(Undefined)
- 虚拟机栈(JVM Statcks)
- 线程私有,一个虚拟机栈对应一个线程//当前cpu调度的叫做:活动线程
- 生命周期和线程相同
- 包含多个栈帧,一个栈帧对应一个方法(Stack Frame):
- 作用:支持虚拟机进行方法调用和方法执行的数据结构
- 结构:
- 方法的局部变量表(Local Variable Table)
- 定义:一组变量值存储空间
- 作用:存放方法参数和方法内定义的局部变量
- 包括:
- 八种基本数据类型//64位长度的long和double会占两个局部变量空间(Slot),其余只占用一个
- 对象引用(reference类型)
- 用句柄访问
- 好处:存储稳定的句柄地址,对象被移动时,只会改变句柄中实例数据指针,reference本身不变。//GC时对象移动普遍
- 直接使用指针访问:
- 好处:速度快,节省了一次指针定位的时间开销,eg:HotSpot
- 用句柄访问
- returnAddress类型//指向一条字节码指令的地址
- 包括:
- StackOverflowError: 线程请求的栈深度大于虚拟机允许的深度。
- OutOfMemoryError: 虚拟机栈动态拓展时无法申请到足够内存时。
- 操作数栈(Operand Stack)
- 后入先出
- 执行:
- 随方法和字节码指令执行,
- 入栈:从局部变量表或者对象实例的字段中复制常量或者变量写入到操作数栈,
- 出栈:随计算的进行将栈中的元素出栈到局部变量表或返回给方法调用者
- 动态链接(Dynamic Link)
- Java虚拟机栈中,每个栈帧包含一个指向运行时常量池中该栈所属方法的符号引用,
- 持有引用目的:支持方法调用过程中的动态链接(Dynamic Link)
- 方法出口(Return Address)
- 方法无论正常完成否,都要返回到方法被调用的位置,确保程序继续进行。
- 方法的局部变量表(Local Variable Table)
- 本地方法栈(Native Method Stacks)
- 本地方法栈为虚拟机使用到的本地方法服务
- 相似于虚拟机栈:会抛出StackOverflowError和OutOfMemoryError
- 区别于虚拟机栈(虚拟机栈为虚拟机执行字节码服务)
- 堆(Heap)
- 划分为以下几个子系统
- 类加载
- 目的:把一份被javac编译过的文件通过加载,生成某种形式的class文件的数据结构,送进内存;程序可通过这个数据结构构造出Java对象;该过程在运行时进行,是java动态拓展性根基。
- 作用:
- 把Java字节码文件加载到虚拟机内部
- 特点:
-
- 采用动态加载,动态链接机制//可实现动态代理及类的热替换
-
- 堆存储
- 作用:
- 负责管理Java的对象堆
- 高效管理内存,提供最底层内存分配的高效接口
- 为所有堆分配的对象选择合理高效的对象数据结构编码
- 高效进行自动垃圾收集
- 作用:
- 类加载
- 执行引擎
- 作用:负责执行Java字节码和本地代码
- 本地方法接口
- 作用:Java字节码和本地代码之间的交互
- 线程管理等
- Java多线程实现包括堆Thread线程库的支持,对管程的实现等
- 类加载过程
- 类生命周期:
- 类加载过程仅包含:
- 加载阶段,虚拟机需要完成三件事情:
- 链接
- 验证
- 目的:
- 保证被加载的类的正确性
- 确保class文件的字节流中包含的信息符合《Java虚拟机规范》约束
- 四个阶段:
-
文件格式验证
- 是否符合Class文件格式的规范
- 能被当前版本的虚拟机处理
- 需要验证:魔数OXCAFEBABE 开头、版本号、常量池常量类型是否支持、指向常量的索引值等
-
元数据验证
- 字节码描述的信息符合《Java语言规范》否
- 验证:类是否有父类、父类是否继承了final修饰的类、非抽象类是否实现了父类定义的方法、类是否与父类有矛盾等
-
字节码验证
- 通过数据流分析和控制流分析,确定程序语义是合法的、符合逻辑的
-
符号引用验证
- 发生在:虚拟机将符号引用转化(在解析阶段中发生)为直接引用时
- 验证:是否缺少或者被禁止访问它依赖的某些外部类、方法、字段等资源。
- 如果所引用的类经过反复验证,考虑采用-Xverifynone参数来关闭大部分的类验证措施
-
- 目的:
- 准备
- 目的:
- 给静态变量分配内存//jdk7及以前,在方法区(永久代),jdk1.8后,在堆里
- 设置类变量初始值//按照系统要求
- 目的:
- 解析
- 定义:是Java虚拟机将常量池内的符号引用替换为直接引用的过程
- 符号引用:以一组符号描述所引用的目标,可以是任何形式的字面量,只要无歧义即可
- 直接引用:可以直接指向目标的指针、相对偏移量,或者是一个能间接定位到目标的句柄
- 定义:是Java虚拟机将常量池内的符号引用替换为直接引用的过程
- 验证
- 初始化
- 类加载过程只有加载阶段用户可以自定义类加载器参与,其余完全由虚拟机主导控制
- 初始化阶段开始执行类中定义的java代码//根据程序员自定义的变量赋值要求来
- 类加载后,内存分配:
- 注:.java文件在操作系统运行:
- …
190 次浏览