深入理解Java虚拟机阅读笔记(二.1):Java内存区域与内存溢出异常

第二部分 自动内存管理机制

第二章 Java内存区域与内存溢出异常

2.1 概述

Java的内存管理交付于虚拟机,本章介绍分区有哪些

2.2 运行时数据区

  • 程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器
    • 线程私有:相互独立,互不影响
    • 线程执行的是Java代码时,记录正在执行的虚拟字节码指令的地址;执行Native方法(作用范围无法到达,调用c的库)时,计数器为空
    • 唯一没有规定任何OutOfMemoryError的区域
  • 虚拟机栈(Java Virtual Machine Stacks):Java方法执行的内存模型
    • 线程私有:每个方法运行时都会创建一个栈帧(具体会在后面介绍,可以先看这个链接),用于存储操作数,函数出口…方法调用和完成的过程就是入栈和出栈的过程
    • 局部变量表就是人们常称作的“栈”,其大小于编译期间分配,且运行期间不改变,存储基本数据类型,对象应用,返回地址类型(?)
    • 关于异常:StackOverFlowErrow静态申请时的长度(栈太小) vs OutOfMemeryError动态扩展时的长度(使用的太多)
  • 本地方法栈(Native Method Stack):Native方法执行的内存模型,以此为分界线随着线程而生而亡
  • Java 堆(Java Heap):
    • 所有线程共享,JVM启动时创建,所有的对象实例和数组都在堆上分配
    • Garbage Collected Heap:分代收集算法
    • 逻辑连续,物理不要求,可动态拓展
  • 方法区(Method Area):
    • 所有线程共享,“Non-Heap”
    • 存储已被虚拟机加载的类信息,常量,静态变量,编译后代码
    • 逻辑连续,可动态拓展,不常但需要回收
  • 运行时常量池(Runtime Constant Pool):方法区的一部分
    • 编译期确定的字面量,符号引用,翻译出的直接引用
    • 动态性,将在类加载后进入方法区的运行时存放,如String.intern()
    • JDK8后移至堆区

在这里插入图片描述

2.3 虚拟机对象探秘

  • 对象的创建
    • 检查:指令参数能否在常量池中定位到类的符号引用,该类是否被加载/解析/初始化,如果没有,先进行类加载
    • 分配内存:类加载后内存基本确定啦,即在Java堆中划分
      • 方法:指针碰撞 & 空闲列表->取决于Java堆是否规整,而堆是否规整由所采用的垃圾收集器是否带有压缩整理功能
      • 考虑:线程安全性,通常有两种解决方式,操作原子性&在堆中事先划分本地线程分配缓冲器(TLAB)
    • 初始化+必要的设置:
      • Object Header不进行设置
      • 其它:全部初始化为0
    • <init>方法:invokespecical指令决定(?),一般执行new后会接着执行<init>方法,即按照程序员的想法进行初始化
  • 对象的内存
    • 对象头:
      • Mark Word:自身运行时的数据,如哈希码,锁状态,数组中的长度…设计成非固定的数据结构,根据对象状态复用空间
      • 类型指针:确定该对象是谁的实例,指向类元数据(?),非必须
    • 实例数据:
      • 存储顺序受到JVM分配策略参数定义顺序的影响
      • CompactFields为True时,可以插入到空隙中
    • 对齐填充:不必须,占位符
      在这里插入图片描述
  • 对象的访问:
    • 规定栈上的reference来指向堆中的具体对象
      在这里插入图片描述
    • 句柄访问,稳定地址 & 直接指针访问,速度更快(为什么类型数据在方法区?)
      在这里插入图片描述

2.4 实战

  • 目的:通过代码验证每个区域中存储的内容,遇到内存溢出快速判断溢出位置,及如何处理这些异常
  • 堆溢出:
    • 实践方法:
      • 在虚拟机中设置堆的大小+不能动态拓展(最小==最大即可)+输出内存堆转储快照 :-Xxm20m -Xmx20 -XX:+HeapDumpOnOutOfMemoryError
      • 不断产生对象,使得堆内存溢出
    • 异常信息:java heap space
    • 处理方法:
      • 使用映像分析工具分析转储快照,确定是内存泄漏(对象已死但没有回收)or 内存溢出(对象必须存活)
      • 内存泄漏则寻找对象到GC的引用链
      • 内存溢出则调整堆的大小,以及从代码上控制对象存活周期
  • 栈溢出:
    • HotSpot中不分虚拟机栈和本地方法栈,只由-Xss参数决定
    • 对于单线程而言,减少栈内存or不断定义大量本地变量(局部变量)都会获得StackOverflowError
    • 对多线程而言,分配的栈越大,能承受的线程数量越小,获得OutOfMemoryError,此时需要依靠“减少内存”(减少最大堆,减少每个线程的栈容量)来换得更多线程
  • 方法区和常量池溢出(?):
    • 通过-XX:PermSize来限制方法区大小,JDK“去永久代”后不再复制实例而是只在常量池中记录引用
    • 通过产生大量常量对象或动态类,使得OutOfMemoryError: PermGen space永久代溢出
  • 本机直接内存溢出:Dump文件中没有明显异常且使用了NIO
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值