Java char 数组似乎每个 char 需要超过 2 个字节

标签 java jvm char sizeof primitive

当我运行以下程序时(使用 "java -Xmx151M -cp .com.some.package.xmlfun.Main" 运行):

package com.some.package.xmlfun;
public class Main {

    public static void main(String [] args) {
        char [] chars = new char[50 * 1024 * 1024];

    }
}

我需要将最大内存增加到至少 151M (-Xmx151M)。因此,当我增加数组大小时,需要增加限制:

  • 50 * 1024 * 1024 -> -Xmx151M
  • 100 * 1024 * 1024 -> -Xmx301M
  • 150 * 1024 * 1024 -> -Xmx451M

为什么 java 看起来每个字符需要 3 个字节,而不是文档建议的 2 个字节?

另外,当我类似地创建 long 数组时,它似乎每个 long 需要 12 个字节,而不是 8 个字节,而 int 它需要 6 个字节而不是 4 个字节。通常看起来它需要 array_size * element_size * 1.5

编译- javac\com\som\package\xmlfun\\*java

使用 - java -Xmx151M -cp 运行。 com.some.package.xmlfun.Main

最佳答案

我想您所看到的可以很容易地通过 JVM 中堆的组织方式来解释。

当您将参数 -Xmx 传递给 JVM 时,您正在定义最大堆大小 应该是多少。但是,它与您可以分配的数组的最大大小没有直接关系。

在JVM中,垃圾收集器负责为对象分配内存,并负责清理死对象。垃圾收集器决定如何组织堆。

你通常有一个叫做伊甸园空间的东西,然后是两个幸存者空间,最后是终身一代。这些都在堆里面,GC把最大的堆分给他们。有关这些内存池的更多详细信息,请查看这个出色的答案:https://stackoverflow.com/a/1262474/150339

我不知道默认值是多少,它们可能确实取决于您的系统。我刚刚检查了(使用 sudo jmap PID)内存池如何划分我在运行 Ubuntu 64 位和 Oracle Java 7 的系统上运行的应用程序中的堆。机器有 1.7GB 内存。

在该配置中,我只将-Xmx传递给JVM,GC按如下方式划分堆:

  • 大约 27% 用于伊甸园空间
  • 每个幸存者空间约 3%
  • 大约 67% 是老一代。

如果您有类似的分布,则意味着您的 151MB 中最大的连续 block 位于永久代中,大约为 100MB。由于数组是一个连续的内存块,而您根本无法让一个对象跨越多个内存池,它解释了您所看到的行为。

您可以尝试使用垃圾收集器参数。在此处检查垃圾收集器参数:http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

你的结果对我来说似乎很合理。

关于Java char 数组似乎每个 char 需要超过 2 个字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17344782/

相关文章:

将二进制字符串转换为十六进制字符串 C

将字符转换为二进制文件

Java - 通过 NetBeans 为另一个类中的按钮添加监听器

java - 从java的其他地方访问innerClass中创建的对象

java虚拟机: how to log class unloading

java - 为什么我收到 JVM 最大堆空间错误?

char数组,为什么我必须 "dereference"单个字符的字符串来给它赋值

java - Servlet 到 Spring Servlet : Is it possible to implement GET method using Spring's HttpRequestHandler?

java - 了解同步块(synchronized block)和内在锁

java - 从 csv 文件行创建 Java 对象的开销是多少