jvm開發筆記5 – 虛擬機內存管理
作者:王智通
一、 前言
ajvm是筆者正在開發中的一個java虛擬機, 想通過編寫這個jvm幫助程序員了解jvm的具體實現細節, 它是國內第一個開源的java虛擬機項目:https://github.com/cloudsec/ajvm, 同時筆者把它的開發筆記也分享到了ata上。 在前麵4篇筆記中, 已經實現了class文件加載器, 反匯編器,jvm的crash信息處理, 同時它已經能運行簡單的java代碼了。 在今天的這篇筆記中, 將開始分享ajvm的內存管理模塊是如何編寫的。
二、內存分配
看下麵一段java代碼:
public class test6 { public static void main(String args[]) { int[] data, data1; int i; int num = 0; data = new int[2]; for (i = 0; i < 2; i++) { data[i] = i; } data1 = new int[3]; } }
首先用javac編譯下, 然後用ajvm的反匯編器查看bytecode:
$./wvm -d test/test6.class Diassember bytecode: <init> ()V stack: 1 local: 1 0: aload_0 1: invokespecial #1 4: return main ([Ljava/lang/String;)V stack: 3 local: 5 0: iconst_0 1: istore 4 3: iconst_2 4: newarray 10 6: astore_1 7: iconst_0 8: istore_3 9: iload_3 10: iconst_2 11: if_icmpge 13 14: aload_1 15: iload_3 16: iload_3 17: iastore 18: iinc 3 1 21: goto 0xfffffff4 24: iconst_3 25: newarray 10 27: astore_2 28: return
源碼中data = new int[2];對應的匯編指令為:
4: newarray 10
根據jvm虛擬機規範的描述, newarray指令的作用是, 從操作數堆棧用取出data數組的元素個數,然後根據newarray後麵的type進行計算要申請的內存大小, type的值在虛擬機規範中如下:
#define T_BOOLEAN 4 #define T_CHAR 5 #define T_FLOAT 6 #define T_DOUBLE 7 #define T_BYTE 8 #define T_SHORT 9 #define T_INT 10 #define T_LONG 11
所以10代表這個int類型的數組, 接下來就要給data這個數組從heap中分配內存了。
void *alloc_newarray_memroy(u1 atype, int count) { void *addr = NULL; switch (atype) { case T_BOOLEAN: case T_CHAR: case T_BYTE: addr = (void *)slab_alloc(jvm_thread_mem, count * sizeof(char)); break; case T_SHORT: addr = (void *)slab_alloc(jvm_thread_mem, count * sizeof(short)); break; case T_INT: case T_FLOAT: addr = (void *)slab_alloc(jvm_thread_mem, count * sizeof(int)); break; case T_LONG: case T_DOUBLE: addr = (void *)slab_alloc(jvm_thread_mem, count * sizeof(long long)); break; default: error("bad atype value.n"); return NULL; } return addr; }
ajvm的內存堆用的是slab算法, slab的內存結構如下:
------- ------ ------ ------ |cache|--> |slab| --> |slab| -->|slab| ------- ------ ------ ------ |cache| ----- |cache| ... ----- ------ ------ ------ |cache|--> |slab| --> |slab| -->|slab| ----- ------ ----- ------ |cache| ... ------- |cache| ------- |cache|-->|slab|-->|slab| -->|slab| ------- ------ ------ ------
源碼中的slab.c是它完整的實現, 不熟悉slab的同學請自行google。
三、垃圾回收
gc是java程序員普遍關心的問題, 當內存不夠時, 將會觸發jvm的垃圾回收機製。
ajvm使用最原始的引用計數法, 需要建立一個新的數據結構:
typedef struct jvm_object { int ref_count; CLASS *class; void *addr; int size; struct list_head list; }JVM_OBJECT;
當數組申請完內存後, 將會建立一個新的JVM_OBJECT與其對應, ref_count被初始化為0, addr指向數組的首地址, size表示數組的大小, JVM_OBJECT將會被加入到jvm_obj_list_head鏈表中, 在這將來的垃圾回收時將會用到。
int jvm_interp_newarray(u2 len, char *symbol, void *base) { ... addr = (void *)alloc_newarray_memroy(atype, count); if (!addr) { error("slab alloc failed.n"); return -1; } printf("addr: 0x%xn", addr); new_obj = create_new_obj(addr, count); if (!new_obj) { error("create new obj failed.n"); return -1; } ... }
當數組被引用時, 我們跟數組的地址在JVM_OBJECT鏈表中找到它, 並且把ref_count加1, 表示這個數組在被引用。 比如上麵的:
17: iastore
這條指令就會對data數組進行引用, 我們隻要在iastore的解釋代碼裏, 對data對應的ref_count加1即可:
int jvm_interp_iastore(u2 len, char *symbol, void *base) { int *addr, index, value; if (jvm_arg->disass_class) { printf("%sn", symbol); return 0; } pop_operand_stack(int, value) pop_operand_stack(int, index) pop_operand_stack(int, addr) printf("addr: 0x%xtindex: %dt%dn", addr, index, value); *(int *)(addr + index) = value; if (inc_obj_ref(addr, (&jvm_obj_list_head)) == -1) { jvm_error(VM_ERROR_INTERP, "inc jvm obj ref failed.n"); return -1; } jvm_pc.pc += len; return 0; }
對於數組data1, 同樣進行了內存分配, 但是始終沒有被引用到, 所以data1將會是gc回收時要釋放的對象。
void start_gc(struct list_head *list_head) { JVM_OBJECT *s; struct list_head *p, *q; list_for_each_safe(p, q, list_head) { s = list_entry(p, JVM_OBJECT, list); if (s && s->ref_count == 0) { printf("free addr: 0x%xtsize: %dtref_count: %dn", s->addr, s->size, s->ref_count); list_del(p); free_jvm_obj(s); } } }
這是ajvm最簡單的gc算法了, 後續將會對其進行優化。
四、演示執行
下麵是ajvm對上述java代碼的解釋和執行過程:
$./wvm -c test test6 jvm pc init at: 0x630510 main ([Ljava/lang/String;)V stack: 3 local : 5 code: 0x3 0x36 0x4 0x5 0xbc 0xa 0x4c 0x3 0x3e 0x1d 0x5 0xa2 0x0 0xd 0x2b 0x1d 0x1d 0x4f 0x84 0x3 0x1 0xa7 0xff 0xf4 0x6 0xbc 0xa 0x4d 0xb1 #local at: 0x630540 #stack at: 0x630554 [ 1] iconst_0 pc: 0x630510 -> 0x3 #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 [ 2] istore pc: 0x630511 -> 0x36 #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 [ 3] iconst_2 pc: 0x630513 -> 0x5 #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x2 0x0 0x0 [ 4] newarray pc: 0x630514 -> 0xbc #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x2 0x0 0x0 #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 [ 5] astore_1 pc: 0x630516 -> 0x4c #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x0 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 [ 6] iconst_0 pc: 0x630517 -> 0x3 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 [ 7] istore_3 pc: 0x630518 -> 0x3e #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 [ 8] iload_3 pc: 0x630519 -> 0x1d #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 [ 9] iconst_2 pc: 0x63051a -> 0x5 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x2 0x0 [ 10] if_icmpge pc: 0x63051b -> 0xa2 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x2 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 [ 11] aload_1 pc: 0x63051e -> 0x2b #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 [ 12] iload_3 pc: 0x63051f -> 0x1d #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 [ 13] iload_3 pc: 0x630520 -> 0x1d #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 [ 14] iastore pc: 0x630521 -> 0x4f #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 [ 15] iinc pc: 0x630522 -> 0x84 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x0 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x0 0x0 0x0 [ 16] goto pc: 0x630525 -> 0xa7 [ 17] iload_3 pc: 0x630519 -> 0x1d #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x1 0x0 0x0 [ 18] iconst_2 pc: 0x63051a -> 0x5 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x1 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x1 0x2 0x0 [ 19] if_icmpge pc: 0x63051b -> 0xa2 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x1 0x2 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x1 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x1 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x0 0x0 0x0 [ 20] aload_1 pc: 0x63051e -> 0x2b #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x0 0x0 [ 21] iload_3 pc: 0x63051f -> 0x1d #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x1 0x0 [ 22] iload_3 pc: 0x630520 -> 0x1d #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x1 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x1 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x1 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x1 0x1 [ 23] iastore pc: 0x630521 -> 0x4f #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x1 0x1 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x1 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x1 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x627c20 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x0 0x0 0x0 [ 24] iinc pc: 0x630522 -> 0x84 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x1 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x0 0x0 0x0 [ 25] goto pc: 0x630525 -> 0xa7 [ 26] iload_3 pc: 0x630519 -> 0x1d #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x2 0x0 0x0 [ 27] iconst_2 pc: 0x63051a -> 0x5 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x2 0x0 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x2 0x2 0x0 [ 28] if_icmpge pc: 0x63051b -> 0xa2 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x2 0x2 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x2 0x0 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x2 0x0 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x0 0x0 0x0 [ 29] iconst_3 pc: 0x630528 -> 0x6 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x3 0x0 0x0 [ 30] newarray pc: 0x630529 -> 0xbc #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x3 0x0 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x627c80 0x0 0x0 [ 31] astore_2 pc: 0x63052b -> 0x4d #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x627c80 0x0 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x0 0x2 0x0 #stack: 0x0 0x0 0x0 #local: 0x0 0x627c20 0x627c80 0x2 0x0 #stack: 0x0 0x0 0x0 [ 32] return pc: 0x63052c -> 0xb1 #local: 0x0 0x627c20 0x627c80 0x2 0x0 #stack: 0x0 0x0 0x0 jvm stack depth is zero. interpret bytecode done.
最後更新:2017-04-03 07:57:05
上一篇:
利用objc的runtime來定位次線程中unrecognized selector sent to instance的問題
下一篇:
jQuery插件treeview點擊節點名稱不展開、收縮節點
Hadoop簡介
《Apache Flink官方文檔》 Apache Flink介紹
破解棄風棄光瓶頸 未來15年風光發電“風光”無限
RTLinux—基於Linux內核的實時操作係統RTLinux
《我的前半生》其實是一部披著職場勵誌外衣的《霸道總裁愛上我》
SOAP-Simple Object Access Protocol(簡單對象訪問協議)
H.265編解碼給視頻會議行業帶來的改變
Stream Processing for Everyone with SQL and Apache Flink
如何通過自定義MessageFilter的方式利用按鍵方式操作控件滾動條[附源代碼]
四層體係結構介紹