JVM内存模型和内存溢出

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40369829/article/details/80457656

运行时数据区域

  • 分为线程共享和线程隔离的区域。
    180525.memory.png

程序计数器

  • 可看做当前线程所执行的字节码的行号指示器。
    • 线程执行java方法时:虚拟机字节码指令的地址。
    • 线程执行native方法时:空(undefined)。
  • 唯一没有规定任何OutOfMemoryError的区域。

虚拟机栈

  • 描述java方法执行的内存模型:每个方法执行时创建栈帧,存储局部变量表、操作数栈、动态链接、方法出口。
  • 局部变量表存储基本数据类型、引用类型,其中64位的long和double占用2个局部变量空间。
  • 异常:
    • StackOverflowError:线程请求的栈深度大于虚拟机所允许的深度。
    • OutOfMemoryError:虚拟机栈扩展时无法申请到足够的内存。

本地方法栈

  • 类似java虚拟机栈,但是使用native方法服务。
  • Sun的HotSpot 虚拟机将本地方法栈和虚拟机栈合并

  • 存储对象实例和数组(JIT编译器的优化使得对象并不一定存储在堆上)。
  • OutOfMemoryError:堆中没有内存完成实例的分配,并且堆无法扩展。

方法区

  • 存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译的代码等。
    • JIT:将热点代码编译成平台相关的机器码。
  • 内存回收的目标:常量池的回收、类型的卸载。
  • OutOfMemoryError:方法区无法满足内存分配需求。

运行时常量池

  • 方法区的一部分,存放编译期生成的的字面量和符号引用,或者运行期间产生的常量(String.intern()方法)。

直接内存

  • 不是虚拟机运行时数据区的一部分,可以通过NIO分配和操作这一堆外内存。
  • OutOfMemoryError:各个内存区域的总和大于物理内存的限制。

对象的创建、布局、访问

  • 基于HotSpot虚拟机讨论,普通java对象,不包括数组、Class对象。

创建

  1. 类加载检查。检查常量池中是否有对应的类的符号引用,并且这个类是否已被加载、解析、初始化。如没有,执行类加载。
  2. 分配内存。内存规整时使用指针碰撞,内存不规整时使用空闲列表,两个以上的对象同时分配内存时,需要注意线程安全,解决方法:
    1. 同步内存分配动作:CAS和失败重试,保证更新的原子性。
    2. 每个线程预先分配本地线程分配缓冲(Thread Local Allocation Buffer, TLAB),在各自的TLAB上分配内存,只有分配新的TLAB时,才需要同步锁定。
  3. 初始化零值。除对象头之外的内存空间初始化,保证对象的实例字段不附初始值就可以使用。也可以在TLAB分配时进行。
  4. 设置对象头。包括属于的类、如何找到类的元数据、对象哈希码、对象GC分代年龄、偏向锁等。
  5. 执行init方法。按照程序员意愿初始化。

布局

  • 对象头
    • 对象自身运行时数据。哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
    • 类型指针。指向类元数据,数组还需要包含数组长度。
  • 实例数据。定义的各种类型字段,存储顺序受虚拟机分配策略和源码中的定义顺序影响,hotspot中相同宽度的字段分配到一起,父类中的变量在子类之前。
  • 对齐填充。HotSpot内存管理系统要求对象的大小必须是8字节的整数倍。

访问

  • 句柄访问。划分句柄池和实例池,reference存储对象句柄地址,句柄包含对象实例数据和类型数据的地址。
    180525.jb.png
  • 直接指针访问。reference存储对象地址,包含指向类型数据的指针。
    180525.pointer.png
  • 句柄访问的优势:对象移动时只会改变句柄中的实例数据指针,reference本身不变。
  • 直接指针访问优势:节省一次指针定位开销,速度更快。HotSpot使用直接指针访问

OutOfMemoryError异常

  • 堆溢出:不停创建对象,并维持 GC Roots 到对象之间的引用避免对象被回收。
  • 栈溢出:
    • 递归过深。
    • 创建过多线程。这是由于栈的空间被每个线程瓜分。
  • 方法区和运行时常量池溢出:
    • String.intern()方法,在常量池中记录首次出现的实例的引用。
    • cglib产生大量的动态类。
  • 本机直接内存溢出:Unsafe实例分配过多内存。
  • 溢出实例
阅读更多

没有更多推荐了,返回首页