JVM 01 运行区域

Java 虚拟机 跨平台

虚拟机隐藏平台差异,解决不同平台代码运行结果不一致问题,实现Write Once, Run Anywhere,实现用户代码跨平台。它本身是一个操作系统上的应用程序,将字节码文件翻译成特定机器的机器码。

Java 虚拟机 运行时内存区域

虚拟机隐藏内存区域,自动实现内存分配与垃圾回收,使用户专注逻辑实现。

JVM 将运行时数据区分成五块:堆,方法区,虚拟机栈,本地方法栈,程序计数器。

堆是内存区域最大的一块,存放对象实例。所有线程共享。它是垃圾回收器 GC 主要管理的区域。堆中也存在线程私有区域(Thread Local ALlocation Buffer)以提升效率。Java 参数 -Xmx -Xms 可以设定 Java 堆大小。

方法区也是线程共享区域。相对于堆,垃圾回收没有那么频繁,条件也更苛刻。它存放存储虚拟机加载的类型信息,常量,静态变量,即时编译器代码缓存。垃圾回收主要针对常量池和类型卸载。JVM 将字节码文件中的字面量,符号引用放入运行时常量池。内存不足也报OOM。

虚拟机栈对应线程。每个线程一个栈,且二者生命周期相同。线程执行的方法对应栈帧。栈帧保存局部变量表,操作数栈,返回地址等。调用和返回方法对于栈帧入栈和出栈。如果无限递归,栈深度超出阈值,报StackOverflowError。如果内存不足,OOM。

局部变量表存放方法所需的局部变量和返回地址。对于基本类型,直接存放值,对于引用类型,存放指针。局部变量表基本单位是四字节的 slot。小于四字节的 boolean,byte,char,short 变量也占据一个 slot。

本地方法栈与虚拟机栈类似,执行的是 native 方法,即非 Java 方法。

程序计数器指示当前线程执行字节码行号,用于控制程序流程。线程上下文切换期间记录当前线程执行行号,下次获取时间片后从当前行号继续执行。程序计数器不会内存溢出,线程私有。

直接内存不是虚拟机运行数据区一部分,它不由 JVM 管理,不受 JVM 大小限制。NIO 使用本地方法分配堆外内存(即直接内存,机器直接分配的内存),通过堆内的 DirectByteBuffer 对象引用堆外内存,避免数据在堆内堆外来回复制。

对象的创建

第一步,要求虚拟机已经加载类。

第二步,为对象分配内存。类加载时就确定大小。分配内存的方法有:指针碰撞和空闲列表。指针碰撞:将堆分为两块,一块已分配,另一块未分配,指针为边界,两块不能有交错。移动指针分配空空闲内存。空闲列表:已分配与未分配交错,维护一个列表,记录可用列表块。虚拟机采用CAS+重试实现线程安全地分配内存。

第三步,初始化内存,将实例字段初始化为零值。

第四步,设置对象头。

第五步,执行构造函数。

对象布局

对象在堆内存中分三块:对象头,实例数据,对齐填充。对象头包含两部分:对象运行时数据和类型指针。运行时数据包括:GC 年龄,哈希码,锁状态。类型指针指向类型元数据。如果是对象是数组,还包含数组长度。

实例数据包含对象字段。父类定义的变量在子类之前,相同长度的字段总是分配在一起。

对齐填充:对象起始地址必须是八字节的整数倍。

相关推荐
三品吉他手会点灯2 小时前
C语言学习笔记 - 50.流程控制4 - 流程控制为什么非常非常重要
c语言·开发语言·笔记·学习
huangdong_3 小时前
电商平台图片URL原图转换技术深度解析:从缩略图到高清原图的完整方案
java·后端·spring
記億揺晃着的那天4 小时前
Java 调用外部 Go 程序的实践:ProcessBuilder 在生产环境中的应用
java·golang·processbuilder
JAVA面经实录9174 小时前
Java 数据结构与算法 (终极完整学习文档)
java·数据结构·算法
JAVA面经实录9174 小时前
操作系统面试题
java·服务器·数据库·计算机网络·面试
一杯奶茶¥5 小时前
基于springboot的失物招领管理系统带万字文档 校园失物招领管理系统 失物认领管理系统java springboot vue
java·vue.js·spring boot·java项目
在放️5 小时前
Python 爬虫 · 第三方代理接入与合规使用
开发语言·爬虫·python
不能只会打代码5 小时前
边缘视频分析平台的架构设计与性能优化——从750ms到190ms的调优之路
java·spring boot·redis·性能优化·边缘计算·物联网竞赛
小刘|5 小时前
Spring AI Alibaba 集成和风天气 API 实战
java·服务器·前端
KANGBboy5 小时前
java知识五(继承)
java·开发语言