Java内存区域-读书笔记《深刻理解java虚拟机》

运行时数据区域

程序计数器

  • 能够看做是当前线程所执行的字节码的行号指示器
  • 线程私有,每条线程都有独立的程序计数器
  • 惟一没有OOM状况区域(java虚拟机规范)

java虚拟机栈

  • 线程私有
  • 描述的是Java方法执行的内存模型
    • 每一个方法执行时建立栈帧,用于存局部变量表、操做数栈、动态连接、方法出口等
    • 局部变量表在编译时完成分配
  • 两种异常
    • StackOverflowError:栈深度超过规定
    • OutOfMemoryError

本地方法栈

  • native方法,相似java虚拟机栈

java堆

  • 全部线程共享
  • 也称:GC堆
  • 分为:
    • 新生代
    • 老年代
  • 逻辑上连续,物理上能够不连续的内存空间
  • -Xmx、-Xms控制
  • 有OOM

方法区

  • 全部线程共享
  • 习惯称为:永久代,喜欢用永久代来实现方法区而已
  • 用于存储:
    • 类信息
    • 常量
    • 静态变量
    • 即时编译器编译后的代码
    • 等等
  • 有OOM

运行时常量池

  • 方法区的一部分
  • 用于存放编译期生成的各类字面量符号引用
  • 不必定只有编译期才能产生,运行时也可能,例:String.intern()方法
  • 有OOM

直接内存

  • DirectMemory
  • 不是虚拟机运行时数据区一部分
  • 也不是java虚拟机规范中定义的区域
  • 有OOM
  • 不受java堆大小限制

对象建立

给对象分配内存

  • 指针碰撞:java堆中内存是绝对规整(已分配与空闲分别在两边)
    • 垃圾收集器带压缩整理
  • 空闲列表:不规整,必须维护一个列表,记录哪些内存可用
    • 垃圾收集器:Mark-Sweep 标记清除
  • 并发状况
    • 分配时同步
    • 每一个线程预先分配一块内存(TLAB)
  • 分配完成后,内存空间初始化为零值,若是是TLAB,可提早置TLAB时进行
    • 这就是对像实例字段不赋值也有初始值的缘由
  • 而后对对象进行必要的设置,如对象是哪一个类的实例等,存放在对象头中

对象的内存布局

  • 对象头(Header)
    • 第一部分存储对象自身的运行时数据
      • 哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等
      • 这部分数据长度在32位和62位(未开启压缩指针)中分别是32bit和64bit
      • 官方称为:Mark Word
      • 非固定的数据结构
    • 另一部分是类型指针
      • 指向它的类元数据的指针,经过这个肯定是哪一个类的实例
      • 并非全部虚拟机实现都必须在对象数据上保留类型指针
    • 若是是数组,对象头中还必须有一块用于记录数组长度的数据
  • 实例数据
    • 各类类型的字段内容
      • 父类中定义的变量出如今子类以前
      • 存储顺序受虚拟机分配策略参数(FieldsAllocationStyle)和在源码中定义的顺序影响
      • HotSpot虚拟机默认分配策略:
        • longs/doubles、ints、shorts/chars、bytes/booleans、oops
        • 相同宽度字段老是分配到一块儿
  • 对齐填充
    • 不是必然存在的
    • 也没有特别含义
    • 占位符做用
    • 使对象大小必须为8字节整数倍

对象访问定位

  • 句柄访问
    • java堆中分一块内存做为句柄池
      • 对象实例地址
      • 对象类型地址
    • 对象移动时,只需改变句柄中实例数据指针
  • 直接指针访问
    • 堆对象中必须考虑如何放访问类型数据相关信息
    • HotSpot使用
    • 速度快
相关文章
相关标签/搜索