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.

 

时间: 2024-09-20 19:29:27

jvm开发笔记5 &#8211; 虚拟机内存管理的相关文章

JVM学习笔记(三)------内存管理和垃圾回收【转】

转自:http://blog.csdn.net/cutesource/article/details/5906705 版权声明:本文为博主原创文章,未经博主允许不得转载. JVM内存组成结构 JVM栈由堆.栈.本地方法栈.方法区等部分组成,结构图如下所示:   1)堆 所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx和-Xms来控制.堆被划分为新生代和旧生代,新生代又被进一步划分为Eden和Survivor区,最后Survivor由From Space和To Space组成,结

JVM学习笔记(四)------内存调优

首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提供的内存查看工具,比如JConsole和Java VisualVM. 对JVM内存的系统级的调优主要的目的是减少GC的频率和Full GC的次数,过多的GC和Full GC是会占用很多的系统资源(主要是CPU),影响系统的吞吐量.特别要关注Full GC,因为它会对整个堆进行整理,导致Full GC

JVM学习笔记(四)------内存调优【转】

转自:http://blog.csdn.net/cutesource/article/details/5907418 版权声明:本文为博主原创文章,未经博主允许不得转载. 首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提供的内存查看工具,比如JConsole和Java VisualVM. 对JVM内存的系统级的调优主要的目的是减少GC的频率和Fu

JVM学习笔记(一)——内存模型

对于Java程序员来说,他们相比C++程序员最幸福的一点就是不用自己管理内存,内存的分配和回收都由虚拟机完成.然而,正是由于该原因,一旦虚拟机内存管理出现问题,比如出现内存泄漏或溢出,排查起来将是非常困难的.所以尽管不用亲自动手管理内存,但是了解虚拟机的内存管理机制还是很有必要的. 运行时数据区域 首先来看下Java虚拟机在运行时的数据区域划分,Java虚拟机在Java程序运行时会将内存区域划分成若干个不同的区域,各自负责不同的职责. 1.1 程序计数器 程序计数器(PC)的概念比较简单,记录当

jvm开发笔记3&amp;#8212;java虚拟机雏形

作者:王智通   一.背景 笔者希望通过自己动手编写一个简单的jvm来了解java虚拟机内部的工作细节毕竟hotsopt以及android的dalvik都有几十万行的c代码级别. 在前面的2篇开发笔记中已经实现了一个class文件解析器和一个java反汇编器 在这基础上 java虚拟机的雏形也已经写好.还没有内存管理功能 没有线程支持.它能解释执行的指令取决于我的java语法范围 在这之前我对java一无所知 通过写这个jvm顺便也把java学会了 它现在的功能如下 1.java反汇编器 山寨了

web项目部署后heap溢出(jconsole java虚拟机内存管理 tomcat内存管理)

阶段性完成编码工作后,打算将项目部署到生产机上看看效果遇到了问题:原本在测试机的eclipse环境能够正常运行的web项目,打包成war文件部署在tomcat上运行后,报错:Java heap space在浏览器上,访问tomcat上部署的web项目时,在浏览器上显示的报错信息.简单的翻译过来就是java的heap溢出.为什么会heap溢出?怎么解决这个问题? 原理上说,java语言环境下开发的web项目,运行在tomcat服务器上.tomcat这个服务器软件,运行在jvm上,而jvm运行在操作

jvm开发笔记4&amp;#8212;jvm crash信息处理

作者:王智通   ajvm是一个笔者正在开发中的java虚拟机, 用c和少量汇编语言编写, 目的在于探究一个可运行的java虚拟机是如何实现的, 目前整个jvm的source code代码量在5000行左右, 预计控制在1w行以内,只要能运行简单的java代码即可.笔者希望ajvm能变成一个教学用的简单java虚拟机实现, 帮助java程序员在陷入庞大的hotspot vm源码之前, 能对jvm的结构有个清晰的认识. ajvm是笔者利用业余时间编写的, 每次完成一个重要功能都会以笔记的形式发布到

jvm开发笔记1&amp;#8212;class文件解析器

作者:王智通   笔者最近对java虚拟机产生了浓厚的兴趣, 想了解下最简单的jvm是如何写出来的,于是看起了<java虚拟机规范>,这个规范如同intel开发手册一样,是每个jvm开发人员必须掌握的. 要想翻译执行java byte code, 首先得从java class文件中把Code属性解析出来才行. 在笔者看来, java的class文件结构着实比elf文件结构复杂很多,不过在复杂的结构, 只要耐心对照着手册中的结构一一解析即可, 经过几天的努力, 用c实现了一个class文件解析器

《iOS应用开发》——2.3节内存管理

2.3 内存管理 iOS应用开发 我不是吓唬你们.在iOS 5.0系统之前,内存管理毫无疑问是iOS开发最困难的部分.简而言之,问题是这样的.无论何时你创建了一个变量,你就要在内存中给它分配一定的空间.对于局部变量来说,我们通常使用栈上的内存,这些内存是自动管理的,当函数返回时,函数中定义的任何局部变量都会从内存中自动删除. 这听起来很棒,但是栈有两个严重的局限.首先,它的空间非常有限,如果用尽了内存,应用程序就会崩溃.其次,这些变量很难共享.请记住,函数使用值传参和返回.这意味着所有传入函数或