美文网首页
《深入理解JVM虚拟机》 - JVM内存管理之内存分区

《深入理解JVM虚拟机》 - JVM内存管理之内存分区

作者: 陈菲TW | 来源:发表于2020-02-24 18:28 被阅读0次

新冠肺炎疫情,假期延长+在家办公=3周看完《深入理解JVM虚拟机》:这本很早之前就在我的待办事项里的书。

JVM虚拟机有虚拟机规范和多种商业虚拟机实现版本,本书主要以HotSpot为例进行讲解(HotSpot本身用C++/C语言实现)

一、 自动内存管理机制

运行时的内存分区包括:

1)程序计数器:线程私有区域,指示当前线程执行的字节码行号;

2)栈:存放栈帧(方法模型),包含方法的操作数、局部变量、返回结果等;方法的调用、返回对应入栈、出栈。线程调用方法过深,超过最大深度,触发StackOverflow;若栈内存允许动态扩展,但超过了最大内存,则触发OutOfMemory异常。配置参数:-Xss

3)本地方法栈:类似栈,对应本地native方法(不是由java语言实现,而是由例如c/c++实现)。配置参数:-Xoss

4)堆:存放对象和数组,空间大,线程间共享。垃圾回收的主战场,GC大多采用分代收集算法,相应的堆分为老年代和新生代。堆内存可以不连续(但堆中对象内存空间需要连续);超过内存大小时,触发OutOfMemory异常。配置参数:-Xms/mx,二者相等则避免堆自动扩展;-Xmn配置新生代。

5)方法区:存放编译后的方法代码、类信息(类名、访问修饰符、字段描述、方法描述等)、常量、静态变量。线程间共享;垃圾回收较少,主要针对常量回收和类卸载,又称永久代。方法区包括常量池(String.intern-查看常量池是否存在相同字面值,存在则复用常量池中的常量);配置参数:MaxPermSize/PermSize

6)直接内存:NIO使用Native函数分配的堆外内存,通过堆上的DirectByteBuffer对象引用从而进行操作。配置参数:MaxDirectMemorySize,默认值为-Xmx

二、对象

1. 创建:当虚拟机遇到new指令,执行下列步骤:

1)检查指令参数(类名)能否定位到常量池中的类,类是否已被加载、解析、初始化,没有则执行类加载。

2)分配内存:对象需要连续的内存空间。所需内存大小在类加载后可确定;根据堆是否规整(GC是否具有压缩整理功能)来决定采用指针碰撞或空闲列表分配方式。指针碰撞:假设堆规整的分为用过和没用过的内存,指针指示分界点,那么分配内存就是把指针向空闲区移动所需分配大小;空闲列表:假设堆不规整,通过列表指示可用内存,找到一块足够的内存分配给新生对象,同时更新空闲列表。本地线程分配缓冲TLAB(Thread Local Allocation Buffer)用于解决线程安全问题,在堆中为各线程划分区域,线程需要分配内存时优先在TLAB分配,TLAB用完后结合同步机制。配置参数:-XX:+/-UseTLAB

3)将分配的内存初始化。保证对象实例不赋初值时,程序能访问到零值。

4)设置对象头,包括对象运行时数据:哈希值、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、时间戳;类型指针:对象指向类的元数据的指针

5)虚拟机执行构造函数,按照程序员的意愿进行初始化。

2. 对象的内存布局

包括:对象头,实例数据和对齐填充三部分。其中实例数据存储代码中定义的字段值,存储顺序由虚拟机分配策略(相同宽度的字段分配在一起)和字段定义顺序决定。由于虚拟机要求对象起始地址是8字节的整数倍,因此需要填充字段。需要注意的是:方法属于类,而不是对象,因此存储在方法区。

3. 对象的访问定位

程序根据栈上的reference操作堆上的对象。两种引用方式:

1)句柄:划分一块堆内存作为句柄池,句柄包括对象和类的地址;reference指向句柄。好处是对象被移动时(GC会频繁移动对象),reference不需要改变。

2)直接指针:reference存储对象地址,对象内存中包含类地址。好处是速度快,节省一次指针定位开销。

三、常见的OOM异常

1. 堆溢出(常见)

错误提示:java heap space。

解决方式:使用内存映像分析工具分析到底是出现了内存泄漏还是内存溢出;如果是内存泄漏,查看泄漏对象到GC root到引用链,定位泄漏代码的位置。如果是内存溢出,查看虚拟机当前设置的堆参数,与物理机内存比较是否可以调大,并且从代码层面查找是否对象持有时间过长可以优化。

2. 栈和本地方法栈溢出

单线程(罕见):栈帧太大/栈空间太小触发StackOverflow异常。栈最大深度通常在1000-2000,能满足多数应用场景。

多线程(OOM):OS分配给进程的内存有限。栈内存=进程内存总量-最大堆内存-最大方法区内存=单个线程栈内存*线程数。解决方案包含:提高进程内存总量(通过使用64位);减少最大堆内存;减少最大方法区内存;减少线程数;减少栈容量等。

3. 方法区和运行时常量池溢出

诊断方式:Perm Gen space

4. 直接内存溢出

诊断方式:Heap Dump文件小,无明显异常,程序中直接/间接使用了NIO。

相关文章

  • Android性能优化-内存泄漏的几个案例

    JVM内存管理 Java采用GC进行内存管理。深入的JVM内存管理知识,推荐《深入理解Java虚拟机》。 关于内存...

  • 深入理解 JVM 之 JVM 内存结构

    深入理解 JVM 之 JVM 内存结构 Java 虚拟机在运行 Java 程序 时,把它所管理的内存划分为若干个不...

  • 初见JVM内存区域

    初见JVM内存区域 JVM一个重要的机制就是自动内存管理机制,为了深入理解JVM的内存管理机制,了解JVM的内存...

  • JVM内存结构

    以下信息摘录自:深入理解JVM的内存结构及GC机制 JVM内存管理 根据JVM规范,JVM把内存区域划分成了以下几...

  • Java内存模型(JMM)

    Java内存模型(JMM) 我们常说的JVM内存模式指的是JVM的内存分区;而Java内存模式是一种虚拟机规范。 ...

  • JMM内存模型详解

    Java内存模型(JMM) 我们常说的JVM内存模式指的是JVM的内存分区;而Java内存模式是一种虚拟机规范。 ...

  • BiBi - JVM -2- 对象

    From:深入理解Java虚拟机 目录BiBi - JVM -0- 开篇BiBi - JVM -1- Java内存...

  • BiBi - JVM -3- 垃圾收集算法

    From:深入理解Java虚拟机 目录BiBi - JVM -0- 开篇BiBi - JVM -1- Java内存...

  • BiBi - JVM -4- HotSpot JVM

    From:深入理解Java虚拟机 目录BiBi - JVM -0- 开篇BiBi - JVM -1- Java内存...

  • BiBi - JVM -5- 垃圾回收器

    From:深入理解Java虚拟机 目录BiBi - JVM -0- 开篇BiBi - JVM -1- Java内存...

网友评论

      本文标题:《深入理解JVM虚拟机》 - JVM内存管理之内存分区

      本文链接:https://www.haomeiwen.com/subject/ucybqhtx.html