- Java虚拟机管理的内存区域包含以下几个运行时数据区域
- 程序计数器
- 可以看做是当前线程所执行的字节码的行号指示器
- 每条线程都有一个独立的程序计数器,各线程之间互不影响,独立存储
- 此内存区域是唯一一个没有在Java中规定任何OutOfMemoryError情况的区域
- Java虚拟机栈
- 也是线程私有的,他的生命周期与线程相同
- 每个方法执行时都会创建一个栈帧用于存储有局部变量表,操作数栈,动态链接等
- 局部变量表所需的空间在编译期就已经确定,所以每个方法创建的栈帧大小是固定不变的,方法运行期间不会改变局部变量的大小
- 如果栈的深度超过了虚拟机允许的范围则抛出 StackOverflowError
- 如果栈内存扩展时无法申请更多的内存则会抛出OutOfMemoryError
- 本地方法栈
- 类似于Java虚拟栈,不过其中运行的是本地方法
- Java堆
- 在虚拟机启动时创建,此内存的唯一目的就是存放对象实例
- 各个线程共享的内存区域
- 所有对象实例及数组都要在堆上分配
- 当堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出O utOfMemoryError
- 方法区
- 各个线程共享的内存区域
- 用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据
- HotSpot中引入了永久代,即将GC扩展至方法去,同时可以设置永久代的最大限量。其余虚拟机方法区只要不达到内存极限均可.
- 方法区常量池
- 存储编译器产生的各种字面量和符号易用
- 受方法区内存限制,超出时抛出OutOfMemoryError
- 具有动态性,运行期间也能将新的常量放入池中
- 各个线程共享的内存区域
- 直接内存
- 各种IO流之类的使用直接内存,不收Java虚拟机管理
- 设置虚拟机参数是应考虑到直接内存的使用
- 各种IO流之类的使用直接内存,不收Java虚拟机管理
- 程序计数器
- Java虚拟对象
- 对象的创建
- 检查对应的类是否已经加载,解析和初始化过
- 为对象分配内存,内存大小是固定的
- 内存分配完毕后将分配到的内存空间都初始化为零值
- 对对象进行必要的设置,如元数据信息,对象的哈希码,对象的GC分代年龄
- 调用对象构造方法(init)
- 多线程的内存分配
- 虚拟机采用CAS配上失败重试的方式保证更新操作的原子性
- 每个线程预先留有一块内存作为分配使用
- 对象的内存布局
- 对象头
- 一部分存储哈希码,GC年代标志,线程持有的锁,偏向线程ID,偏向时间戳
- 对象指向它的类元数据的指针
- 对象真正存储的有效信息
- 对齐填充
- 虚拟机的内存管理系统要求对象的其实地址必须是8字节的整数倍
- 对象头
- 对象的访问定位
- 通过栈上的reference数据来操作堆上的具体对象,reference只保存了对象的引用
- 访问对象有两种方式
- 句柄访问,Java堆内存中划出一块内存保存句柄,reference指向对象的句柄地址,再根据句柄找到对象的位置以及对象类型数据
- 直接指针访问,reference存储直接指向对象地址
- 对比两种方式
- 第一种慢,但是对象移动时只用更新句柄即可
- 第二种快(HotSpot就用这种)
- 对象的创建
Java内存区域及内存溢出异常
最新推荐文章于 2024-07-14 22:18:32 发布