天天看点

jvm开发笔记5 – 虚拟机内存管理

作者:王智通

一、 前言

ajvm是笔者正在开发中的一个java虚拟机, 想通过编写这个jvm帮助程序员了解jvm的具体实现细节, 它是国内第一个开源的java虚拟机项目:https://github.com/cloudsec/ajvm, 同时笔者把它的开发笔记也分享到了ata上。 在前面4篇笔记中, 已经实现了class文件加载器, 反汇编器,jvm的crash信息处理, 同时它已经能运行简单的java代码了。 在今天的这篇笔记中, 将开始分享ajvm的内存管理模块是如何编写的。

二、内存分配

看下面一段java代码:

首先用javac编译下, 然后用ajvm的反汇编器查看bytecode:

源码中data = new int[2];对应的汇编指令为:

根据jvm虚拟机规范的描述, newarray指令的作用是, 从操作数堆栈用取出data数组的元素个数,然后根据newarray后面的type进行计算要申请的内存大小, type的值在虚拟机规范中如下:

所以10代表这个int类型的数组, 接下来就要给data这个数组从heap中分配内存了。

ajvm的内存堆用的是slab算法, slab的内存结构如下:

源码中的slab.c是它完整的实现, 不熟悉slab的同学请自行google。

三、垃圾回收

gc是java程序员普遍关心的问题, 当内存不够时, 将会触发jvm的垃圾回收机制。

ajvm使用最原始的引用计数法, 需要建立一个新的数据结构:

当数组申请完内存后, 将会建立一个新的jvm_object与其对应, ref_count被初始化为0, addr指向数组的首地址, size表示数组的大小, jvm_object将会被加入到jvm_obj_list_head链表中, 在这将来的垃圾回收时将会用到。

当数组被引用时, 我们跟数组的地址在jvm_object链表中找到它, 并且把ref_count加1, 表示这个数组在被引用。 比如上面的:

这条指令就会对data数组进行引用, 我们只要在iastore的解释代码里, 对data对应的ref_count加1即可:

对于数组data1, 同样进行了内存分配, 但是始终没有被引用到, 所以data1将会是gc回收时要释放的对象。

这是ajvm最简单的gc算法了, 后续将会对其进行优化。

四、演示执行

下面是ajvm对上述java代码的解释和执行过程: