1

根据我的研究,我知道您可以使用static final修饰符在 Java 中获得几乎类似于 C 的常量值。即static final int my_const_int = 5;

通过实验,我发现你可以用同样的方式创建常量对象,但它需要使用new关键字 iestatic final Color c = new Color(100,100,100,255);

我的问题是:使用这种方法,颜色对象 c 会在运行时分配在堆上,在运行时分配在堆栈上(Java 甚至使用堆栈吗?),还是会在编译时以某种方式评估以减少内存占用?

我是最近转换的 C 程序员,所以虽然我对内存非常了解,但我对 Java 如何使用它却知之甚少。任何见解将不胜感激。

4

3 回答 3

3

所有对象都存储在堆上,即使是对象static final。据编译器所知,对象可能是可变的。

只有原语和引用存储在堆栈上。

在相关说明中,编译器将在使用它们的地方内联原始常量。

于 2013-06-28T20:04:24.150 回答
1

从我从 C 切换到 Java 时:

第一个技巧是忘记所有关于内存的知识,尤其是关于存储常量的最有效方式。Java 非常简单,您无需为此烦恼。第二个技巧是学会随意做所有你在 C 中永远不敢做的简单事情。创建对象并忘记它们:不要担心谁有指向它们的指针,不要担心它们是否已被释放,不用担心你在百万周期循环中反复分配和释放空间。

关于 Java 内存的三件事:

你不能加快速度。 Java 将每个事物放在单独分配的内存中,并通过引用对其进行跟踪。在 C 中,您可以将一组嵌套结构全部排列在一个连续的内存块中。无论您做什么,在 Java 中,同样的事情将是一组指向其他内存块的指针(“引用”),其中许多仍然是更多的指针集。接受。

你不能放慢速度。 Java 优化器会做任何事情来让你的代码运行得更快,而 JVM 优化器会在你的代码运行时做这件事。将对象放在堆栈上(如其他地方所述)是典型的。

(这不是您通常需要考虑的事情,但它可以对基准测试做一些奇怪的事情。JVM 可以巧妙地注意到,当循环运行时,您实际上并没有查看百万数字中的 5 个以上的元素您正在填充的数组,并摇动循环,使其仅运行 5 次来填充这 5 个元素。)

还有一个大的:

你不能把它搞砸! 如果您有一个带有(非空)引用的变量,那很好。对象在那里。它与设置引用时的对象相同。最令人惊讶的是,当你停止使用某些东西时——而且只有当你停止使用它时——空间才会被释放。将一个对数百万个对象的广泛图表的引用归零,然后……噗! 过去了!您可以在不使用更多内存的情况下构建同样大的东西。Java 的一个关键(也许关键)是尽其所能地榨取它。

(免责声明:大型数组和使用它们的东西——ArrayList、HashTable——惹恼垃圾收集器并导致它需要比应有的更多的内存。但以后再担心。)

一般来说,使用诸如“静态”和“最终”之类的词来控制你的程序做什么,而不是试图提高速度或内存使用。指定算法是你的工作。快速运行它是 Java 的工作。

(再次免责声明:如果你保留了太多太大的对象,你耗尽内存。这样做会在不知不觉中产生一种 Java“内存泄漏”——与 C 内存泄漏非常不同。但如果你要去为了减少内存使用,您必须通过重新设计类来做到这一点,而不是重新设计数据原语在类中的存储方式。)

于 2013-06-29T01:29:19.083 回答
1

在 Java 中,所有对象都分配在堆上。唯一一次在堆栈上分配变量是针对本地声明的原语和对堆上对象的本地声明的引用(想想“指针”,但没有指针算术、解引用等)。

另外值得注意的是,由于数组是对象,因此它们也分配在堆中,并且您维护对线程堆栈中指针的引用,即使它是一个原始数组,如int[].

编辑:感谢 Marko 的编辑。Hotspot JVM(可能还有其他)可以根据对象引用是否可以“转义”方法或堆栈帧来执行优化。如果对象的引用没有在堆栈帧之间传递(即它被发布到其他线程),也没有传递给父堆栈帧(即由方法返回),那么该对象被认为是“不可逃避的”并在堆栈帧内分配本身,类似于在 C++ 中在堆栈上分配对象的方式。这是参考

于 2013-06-28T20:05:01.237 回答