Java内存区域及内存溢出异常

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

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值