我对java中的内存分配是在运行时还是编译时发生感到困惑。
例如:
class Test{
int a;
public Test(){
a=10;
}
};
// somewhere else
Test t = new Test();
是a
在运行时分配还是在编译时分配?如果在编译时,如何在直接获取已编译 .class 文件的 VM 上运行 java?
还:
什么时候
a
赋值10
?它如何用于参考变量
t
?
谢谢。
我对java中的内存分配是在运行时还是编译时发生感到困惑。
例如:
class Test{
int a;
public Test(){
a=10;
}
};
// somewhere else
Test t = new Test();
是a
在运行时分配还是在编译时分配?如果在编译时,如何在直接获取已编译 .class 文件的 VM 上运行 java?
还:
什么时候a
赋值10
?
它如何用于参考变量t
?
谢谢。
编译时没有内存分配发生。仅在加载和运行时。
编译时生成 .class 文件就是这样。
请记住,您需要有一个主类来运行程序。当您使用带有 .class 文件的类路径的 Java 运行程序时,将执行诸如加载和链接等步骤,
类加载器将文件加载到 permgen。
当 main 方法被调用时,会创建栈并放置局部变量
当运行时遇到new时,它会在堆上创建对象并在那里分配所需的内存,就像测试所需的内存一样。
局部变量和方法参数(如原语或引用)在编译时理论上在堆栈上分配了一个位置。
在运行时,这不能保证反映它在内存中的布局方式。
堆上的对象分配只发生在运行时。
java怎么可能在直接编译.class文件的VM上运行。
只有 VM 知道如何编译代码,因此无法在编译时进行内存分配。
什么时候赋值 10
在分配发生的行。鉴于它没有被使用,JIT 可以丢弃它,因此它可能根本不会发生。
同样的问题也代表参考变量 t。
t
=
在构造对象之后分配。
在java中,除非创建在运行时创建的对象,否则不会加载类,因此在加载类时,您的任何成员变量(如“a”)将获得空间对于对象而言,它将在运行时分配空间。
好吧,这个有点笨拙,我不确定您是否会从整个线程中得到您想要的确切答案,因为实际上,您要问的是编译器的内部结构,大多数人真的不在乎。
在大多数情况下,Java 编译器使用自动内存管理,因此真正由编译器决定它将做什么或不做什么,并且这可以在版本之间改变。
但在我开始解释之前,我想澄清一下我的符号:
字符串是java中的一种特殊情况,虽然它是一个对象,但它的处理方式可能与其他对象不同。
[object] 有一个特殊的属性。它有一个值和一个标识符,标识符被解析为一个值的过程以及它发生的时间取决于绑定的类型。
有静态绑定,其中绑定可以在编译时解析,其值或方法在编译时是已知的。这也称为“早期”绑定。例如。
整数a = 0;// AND //直接函数调用,例如 print();
还有动态绑定,其中标识符与值或子程序与程序之间的绑定直到运行时才会发生。这也称为“后期”绑定。例如。
public void foo(java.util.List list) { list.add("bar"); }
还有一种混合类型的绑定,但我不打算谈论它,因为我还没有发现 Java 拥有它。
现在,绑定也与作用域密切相关,作用域是变量“存在”在特定作用域中的想法。这是我真的不想讨论的话题(范围界定有点像熊)并使这篇文章成为小说而不是中篇小说。
Java 中内存分配的工作方式取决于以下几点:
如果在编译时已知对 [Object]、[object] 或 [primitive] 的引用,并且是否可能发生静态绑定,则编译器可能会为这些对象分配内存(请注意我没有t 使用括号)在编译时。
如果在编译时无法知道对 [Object]、[object] 或 [primitive] 的引用,并且必须使用动态绑定,那么编译器可能会在运行时为这些对象分配内存。
Java 对待在运行时分配的对象的方式有所不同,这取决于哪个绑定用于什么类型。
总而言之,不用担心。这样做让你很头疼。
如果我对此有任何误解,请有人告诉我。我有点生疏了。