Java 中的静态字符串常量需要内存空间吗?

问题描述 投票:0回答:5

JVM会分配多少内存 1)静态字符串 2) 静态整数

我正在探索这个问题,因为我遇到了堆内存内存不足异常, 我的应用程序中有 8 个常量文件,每个文件几乎有近 300 个静态常量。

将所有常量声明为静态是一个好的做法还是我可以遵循的任何其他做法?

java performance memory-leaks heap-memory
5个回答
7
投票

JVM 将分配多少内存给 1) 静态字符串 2) 静态整数

(为了简单起见,我假设我们正在谈论 32 位 JVM。另请注意,这些数字是近似值,并且特定于 JVM。) 首先是简单的 - 每个静态

Integer

变量占用 4 个字节的内存用于引用,加上 4 个字节 + 1 个对象头(通常为 8 个字节 IIRC)。总计 - 16 字节。

(如果您谈论的是静态 

int

变量,则每个

int
总共 4 个字节。)
静态 

String

变量有点复杂......而且更昂贵:


静态引用变量为4字节。
  • String
  • 对象有 4 x 4 字节字段 + 1 x 2 字对象头:即 24 字节。
    其中一个字段引用一个 char 数组,该数组具有 3 个字的标头,并且需要 
  • (string.length() + 3) / 4
  • 字节来存储内容 - 即 12 + 4 字节的某个倍数。
    如果字符串值是编译时常量,则字符串将被保留,这将为字符串池哈希表条目添加一些额外的字节开销。 (32 字节
    这是一个合理的猜测。)
  • 将所有这些加起来,你会得到(比如说)每个字符串 80+ 字节,具体取决于字符串长度。但几乎所有这些字节都是(内部)字符串本身的表示。由于使用了
static

,因此只有 4 个字节。


我正在探索这个问题,因为我遇到了堆内存内存不足异常,我的应用程序中有 8 个常量文件,每个文件几乎有近 300 个静态常量。

这微不足道。 OOME 几乎肯定是由于其他原因造成的。

将所有常量声明为静态是一个好的做法还是我可以遵循的任何其他做法?

在一定程度上,将实数常量声明为静态是一种很好的做法。

但是,源代码中的大量常量变得难以处理,并且由于字节码文件格式的限制,您最终会遇到编译错误。那时(可能在那之前)您应该将常量从源代码中移出并移入数据库或配置文件中。

在内存使用成为重大问题之前,您可能会遇到字节码格式强加的限制(请参阅

java中方法的最大大小?

)。


4
投票

我会在其他地方寻找内存消耗者。


2
投票

除了字符串本身的字符之外,字符串还包含一些控制字段,但我把它们算作 28 个字节加上另一个嵌入对象(ObjectStreamField),我不确定那有多大,但无论如何可能有几十个字节。每个字符占用 2 个字节。我认为你需要 8 个字节作为句柄。如果你的字符串是什么,也许每个字符串有 20 个字符左右?也许每个字符串有多达 100 个字节。正如 Thilo 所说,2400 个字符串可能听起来很多,但实际上需要数百 kB。除非您谈论的是嵌入手表或某些此类高度受限环境中的 Java,否则很难想象这将成为破坏您记忆的重要因素。


1
投票

最终的,因为你将它们称为常量。 如果将原始类型或字符串定义为常量并且其值在编译时已知,则编译器会用其值替换代码中各处的常量名称。这称为“编译时常数”。对于原始类型不需要使用堆内存。字符串是内部存储的,只需要在堆中存储一份副本。

无论如何,我不相信 8 x 300 字符串会导致内存不足的情况。你的问题一定出在其他地方。

你的常数弦有多大?


0
投票

将常量声明为静态和最终确实是一个很好的做法。例如

public static final String A_STRING = "this String is constant";

注意,“final”修饰符使引用保持不变,而不是对象本身。

© www.soinside.com 2019 - 2024. All rights reserved.