首页 > 代码库 > java内存区域及溢出异常

java内存区域及溢出异常

内存划分:

java虚拟机在执行java程序过程中会把内存分为以下区域进行管理

技术分享

线程私有的
  虚拟机栈
    局部变量表
      基本数据类型
        long和double占用两个slot
      对象引用
      返回地址

    操作数栈
    动态链接
    方法出口等信息

    抛出异常:

      栈深度过大 StackOverflowError
      申请内存空间不足 OutOfMemoryError

  程序计数器

  本地方法栈
线程共享的
  堆
    虚拟机启东时创建
  方法区
    常量池的回收和类型的卸载
    运行常量池:字面量和符号引用 翻译出来的直接引用

  直接内存

    NIO可以使用Native函数库直接分配,这样能显著增加效率,因为不用在java堆和native堆中复制数据

    然而,分配内存时如果直接内存加java内存超过计算机物理内存限制,就会报出OutOfMemoryError

 

 

虚拟机对象:
对象的创建:
  1.new定义到常量池中的一个符号
  2.检查符号代表的类是否被装载 解析 初始化
    如果没有,加载类
  3.加载完类后,为新生对象分配内存(类加载后会确定分配的内存大小)

    内存分配方法:
      如果内存是规整的 指针碰撞(指针移动对象的内存大小的位置)
      如果内存是交错的 空闲列表 列表记录哪些内存是可用的,分配对象实例时分配给足够大的内存给对象,并更新列表

      选择哪种分配方法由java堆是否规整来决定,堆是否规整由java回收器是否采用压缩整理功能决定


    分配内存的线程安全问题
      对分配内存的动作进行同步处理
      TLAB 本地分配缓冲区 每个线程预先分配一块内存,哪个线程要分配内存,就在哪个线程上面分配,只有在TLAB用尽并分配新的TLAB时才需要同步锁
  4.内存分配之后,内存空间都初始化为零值
  5.对对象进行必要设置,设置对象头(类 元数据 hashcode gc年代)

对象的布局:
  对象头
    运行时数据
      HashCode GC分代年龄 锁状态标识 线程持有的锁 偏向线程id 偏向时间戳
    类型指针
      如果是数组,对象头要保存记录数组的长度信息
  实例数据
    虚拟机分配策略
  对齐填充
    hotpot虚拟机需要对象的大小是8个字节的整数倍 对象头正好是8个字节的倍数 如果实例数据没有对齐时,需要用对齐填充来补充


对象的访问定位:
  引用定义在栈上,虚拟机规范没有定义引用以何种方式定位对象位置,由虚拟机自身来完成,主流访问方式两种:
  1.句柄

    技术分享

    好处:对象移动时,只需要改变句柄的实例数据指针,不需要改变栈中本地变量的指针(它指向)

  2.直接指针

    技术分享

    好处 速度更快,节省一次指针定位的时间

 

OutOfMemoryError

VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOutOfMemoryError

java内存区域及溢出异常