JVM 内存分配和管理

君子以自强不息。

JVM 中常见的6种对象类型

ResourceObj: 线程有一个资源空间(Resource Area),一般 ResourceObj 都位于这里。定义资源空间的目的是对 JVM 其他功能的支持,如 CFG、在 C1/C2 优化时可能需要访问运行时信息(这些信息可以保存在线程的资源区)。

StackObj: 栈对象,声明的对象使用栈管理。其实栈对象并不提供任何功能,且禁止 New/Delete 操作。对象分配在线程栈中,或者使用自定义的栈容器进行管理。

ValueObj: 值对象,该对象在堆对象需要进行嵌套时使用,简单地说就是对象分配的位置和宿主对象(即拥有这个ValueObj对象的对象)是一样的。

AllStatic: 静态对象,全局对象,只有一个。值得一提的是 C++ 中静态对象的初始化并没有通过规范保证,可能会有一个问题,就是两个静态对象相互依赖,那么在初始化的时候可能出错。JVM 中的很多静态对象的初始化,都是显式调用静态初始化函数。

MetaspaceObj: 元对象,比如 InstanceKlass 这样的元数据就是元对象。

CHeapObj: 这是堆空间的对象,由 new/delete/free/malloc 管理。其包含的内容很多,比如 Java 对象、InstanceOop)。

对象分配简介

对象分配分为:快速分配和慢速分配。

为了提高效率,无论快速分配还是慢速分配,都应该在 STW 之外调用,即都应该尽量避免使用全局锁,最好满足不同 Mutator 之间能并行分配且无干扰。但实际上堆空间只有一个,所以 JVM 的设计者致力于优秀的内存分配算法,把内存分配算法设计成几个层次,首先进行无锁分配,再进行加锁,从而尽可能地满足并行化分配。

以一个普通的 Java 对象分配为例:

  1. JVM 会先创建 instanceklass,然后通过 allocate_instance 分配一个 instanceOop。
  2. 在 CollectedHeap::obj_allocate 中完成内存分配,如果成功则初始化对象;如果不成功则抛出异常。