我知道Java中的域是在创建对象的时候为其分配空间的,但是我一直不明白方法体内部的局部变量是什么时候为其分配空间的。难道也是在创建对象时分配?还是在该方法被调用时候分配?求解。
方法都是在栈中运行 所以调用时候分配,在方法运行时会创建一个栈帧用于存储局部变量,每个方法中的局部变量所需的内存大小是在编译期确定的。
执行方法体内的代码时,局部变量会保存在JVM栈帧上,方法返回时自动回收。但是局部变量指向的对象是保存在JVM堆中的,由垃圾回收器负责回收。
例如:Test s = new Test(); 这里的引用对象s保存在栈上,实际的Test对象保存在堆中。这两个对象都是在执行到这一行代码的时候分配的空间:在字节码中,先new出Test对象,在堆中分配内存,然后使用dup将其引用压入栈帧的操作数栈,然后调用Test对象的构造函数,然后调用astore将此时的栈顶值弹出存到栈帧的局部变量表中去。
java bytecode 是基于栈的。局部变量区在栈帧里面,同时还有操作数栈和帧数据区。只不过java的栈跟x86的栈不一样的地方是,x86的栈可以拿ebp加偏移来随便访问,java不行,局部变量区和操作数栈都有专门的访问指令,互不相通。
比如
public static void main(String[] args) {
int i = 0;
int j = 4;
int k = i + j;
float a = 0;
float b = 1;
float c = a + b;
long x = 0;
long y = 1;
long z = x + y;
String string = null;
}
会被编译成
public static void main(java.lang.String[]);
Code:
// int i = 0;
0: iconst_0
1: istore_1
// int j = 4;
2: iconst_4
3: istore_2
// int k = i + j;
4: iload_1
5: iload_2
6: iadd
7: istore_3
// float a = 0;
8: fconst_0
9: fstore 4
// float b = 1;
11: fconst_1
12: fstore 5
// float c = a + b;
14: fload 4
16: fload 5
18: fadd
19: fstore 6
// long x = 0;
21: lconst_0
22: lstore 7
// long y = 1;
24: lconst_1
25: lstore 9
// long z = x + y;
27: lload 7
29: lload 9
31: ladd
32: lstore 11
// String string = null;
34: aconst_null
35: astore 13
37: return
一般入门的书不会提及这些,需要你自己拿着jd-gui反编译你写的程序来看。
p.s. dalvik是基于寄存器的模型,和java bytecode 又不一样。这种东西推荐去看《android软件安全与逆向分析》。
好好读读基础知识
方法只有在调用时候才分配空间
所有方法内部成员 都是在栈中 分配
方法结束 所有内部成员 都会出栈