未初始化的原始实例变量是否使用内存?

时间:2014-10-27 10:13:04

标签: java memory-management initialization primitive

在Java中,在没有初始化的情况下声明类级实例变量会花费内存吗? 例如:如果我没有使用int i;对其进行初始化,i = 5;会使用任何内存吗?

详细说明:

我有一个巨大的超级类,许多不同的(没有足够的不同,有自己的超类)子类扩展。有些子类不使用超类声明的每一个原语。我可以简单地将这些原语保留为未初始化,并仅在必要的子类中初始化它们以节省内存吗?

6 个答案:

答案 0 :(得分:72)

您的类中定义的所有成员都具有默认值,即使您没有显式初始化它们,因此它们也会使用内存。

例如,默认情况下,每个int都会初始化为0,并且会占用4个字节。

对于班级成员:

int i;

与:

相同
int i = 0;

以下是JLS关于实例变量的说法:

  

如果类T的字段a是实例变量,则创建新的实例变量a并将其初始化为默认值 (§4.12.5),作为每个新创建的对象的一部分T类或任何类的子类T(§8.1.4)。在完成对象(第12.6节)的任何必要的最终化之后,当实例变量不再被引用时,实例变量将不再存在。

答案 1 :(得分:17)

是的,虽然您没有为其分配任何值,但内存会分配。

int i;

需要32 bit内存(分配)。无论你是否使用它。

  

有些子类不使用超类声明的每个单元。我可以简单地将这些原语保留为未初始化,只在必要的子类中初始化它们以节省内存吗?

同样,无论你在哪里初始化,内存都会分配。

只需要注意的是,只需找到未使用的基元并将其删除即可。

修改 再添加一个不同于原始引用的点,默认值为null,它带有

的内存
 4 bytes(32-bit) 
 8 bytes on (64-bit)

答案 2 :(得分:11)

最初的问题是关于类级别的变量,答案是他们确实使用了空间,但是看看方法范围的变量也很有趣。

我们举一个小例子:

public class MemTest {
    public void doSomething() {
        long i = 0;  // Line 3
        if(System.currentTimeMillis() > 0) {
            i = System.currentTimeMillis();
            System.out.println(i);
        }
        System.out.println(i);
    }
}

如果我们看一下生成的字节码:

  L0
    LINENUMBER 3 L0
    LCONST_0
    LSTORE 1

好的,正如预期的那样,我们在代码中的第3行分配一个值,现在如果我们将第3行更改为(并因编译器错误而删除第二个println):

long i; // Line 3

...并检查字节码然后没有为第3行生成任何内容。因此,答案是此时没有使用内存。事实上,当我们分配给变量时,LSTORE仅在第5行发生。因此,声明未分配的方法变量不会使用任何内存,实际上也不会生成任何字节码。它相当于在您首次分配声明时进行声明。

答案 3 :(得分:6)

是。在您的班级中,即使您没有初始化,变量也会指定为默认值。

在这种情况下,您int个变量将分配给0,每个变量将占用4 bytes

答案 4 :(得分:4)

Java语言规范和Java虚拟机规范都没有指定答案,因为它是一个实现细节。事实上,JVMS §2.7 specifically says

  

对象的表示

     

Java虚拟机不要求任何特定的对象内部结构。

理论上,符合要求的虚拟机可以使用一组位标记来实现具有大量字段的对象,以标记哪些字段已设置为非默认值。最初不会分配任何字段,标志位将全为0,并且对象将很小。首次设置字段时,相应的标志位将设置为1,并且将调整对象的大小以为其腾出空间。 [垃圾收集器已经提供了必要的机制,用于暂时停止运行代码,以便在堆周围重新定位活动对象,这对于调整它们来说是必要的。]

在实践中,这不是一个好主意,因为即使它节省了内存,也是复杂而缓慢的。访问字段需要临时锁定对象以防止由于多线程而导致损坏;然后读取当前标志位;如果该字段存在,则计算设置位以计算所需字段相对于对象基数的当前偏移量;然后阅读该领域;最后解锁对象。

因此,没有通用的Java虚拟机可以做这样的事情。一些具有过多字段的对象可能会从中受益,但即使它们也不能依赖它,因为它们可能需要在不能这样做的公共虚拟机上运行。

在首次实例化对象时为所有字段分配空间的平面布局简单快速,因此这是标准。程序员假设对象以这种方式分配,因此相应地设计他们的程序以最好地利用它。同样,虚拟机设计人员也会进行优化以快速实现这种使用。

最终,字段的平面布局是惯例,而不是规则,尽管无论如何你都可以依赖它。

答案 5 :(得分:2)

在Java中,当您声明类属性String str;时,您声明对对象的引用,但它没有指向任何对象,除非您影响它的值str=value; 。但正如您可能猜到的那样,即使没有指向内存位置,引用也会占用一些内存。