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

时间:2010-10-29 06:04:10

标签: java performance memory-leaks heap

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

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

将所有常量声明为静态或其他任何可以遵循的做法是不错的做法?

5 个答案:

答案 0 :(得分:4)

  

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个字节。
  • 其中一个字段是指一个字符数组,它有一个3字的标题,内容需要(string.length() + 3) / 4字节 - 这是12 + 4字节的倍数。
  • 如果String值是编译时常量,那么String将被实现,这将为字符串池哈希表条目添加一些额外的字节开销。 (32个字节 这将是一个合理的猜测。)

添加所有内容,每个字符串得到(比如说)80+个字节,具体取决于字符串长度。但几乎所有这些字节都是(interned)String本身的表示。只有4个字节是由于使用了static

  

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

那是微不足道的。 OOME几乎肯定是由于别的东西。

  

将所有常量声明为静态或其他任何可以遵循的做法是不错的做法?

最好将实常数声明为静态,直到某一点。

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

在内存使用成为一个重要问题之前,你很可能会遇到字节码格式强加的限制。

答案 1 :(得分:3)

2400字符串常量不会让你内存不足。每个10K,只需24MB。以更常见的100字节速率,它只有240K。

我会在其他地方寻找记忆力。

答案 2 :(得分:2)

字符串对象占用多少空间当然取决于字符串的长度。

除了字符串本身的字符外,一个字符串包含一些控制字段,但我将它们视为28字节加上另一个嵌入对象(ObjectStreamField),我不确定它有多大,但无论如何它可能是一些十几个字节。每个字符占用2个字节。我认为,你需要8个字节的句柄。如果你的字符串是,每个字符大约20个字符左右,那么每个字符串可能有多达100个字节。就像Thilo所说,2400弦可能听起来很多,但它需要数百KB。除非你在谈论嵌入在手表或某些如此高度受限的环境中的Java,否则很难想象这会成为一个重要的因素,会让你的记忆消失。

答案 3 :(得分:1)

我认为这些都是静态 final,因为你将它们称为常量。

如果将基本类型或字符串定义为常量并且该值在编译时已知,则编译器会将代码中的常量名称替换为其值。这称为compile-time constant。对于原始类型,不需要使用堆内存。字符串是实例化的,只需要将一个副本存储在堆中。

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

答案 4 :(得分:0)

你的常量弦有多大?

字符串使用的内存大小为8 * 300 * 2 *平均长度= ~5k *平均长度。使用你所有的记忆似乎不够。

将常量声明为静态,也是最终的确实是一种好习惯。 e.g。

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

注意,它是由'final'修饰符赋予常量的引用,而不是对象本身。