【问题标题】:Java creating byte array whose size is represented by a longJava 创建字节数组,其大小由 long 表示
【发布时间】:2023-03-05 11:00:01
【问题描述】:

我正在尝试创建一个大小为long 类型的字节数组。例如,将其视为:

long x = _________;
byte[] b = new byte[x]; 

显然你只能为字节数组的大小指定int

在有人问我为什么需要这么大的字节数组之前,我会说我需要封装我不写的消息格式的数据,其中一种消息类型的长度是无符号整数 (@987654324 @ 在 Java 中)。

有没有办法创建这个字节数组?

我在想如果没有办法,我可以创建一个字节数组输出流并继续输入字节,但我不知道字节数组的大小是否有任何限制......

【问题讨论】:

  • 大多数 32 位架构上的 unsigned int 仅比 java 中的 int 多一位。 java long 是 64 位的,不适合数组索引。
  • 我意识到这一点,但我不知道如何在不实现我自己的数据类型的情况下完全表示消息指定的数据量。

标签: java arrays byte long-integer


【解决方案1】:

(对于 OP 来说可能有点晚了,但对其他人可能仍然有用)

不幸的是,Java 不支持超过 231-1 个元素的数组。 byte[] 数组的最大消耗为 2 GiB 空间,long[] 数组的最大消耗为 16 GiB。

虽然在这种情况下它可能不适用,但如果数组将是 sparse,您也许可以使用像 Map 这样的关联数据结构来将每个使用的偏移量匹配到适当的价值。此外,Trove 为存储原始值提供了比标准 Java 集合更节省内存的实现。

如果数组不是稀疏的,并且您确实需要内存中的整个 blob,您可能必须使用二维结构,例如Map 匹配偏移量模 1024 到正确的 1024 字节数组。即使对于稀疏数组,这种方法也可能更节省内存,因为相邻的填充单元可以共享相同的Map 条目。

【讨论】:

    【解决方案2】:

    大小为最大 32 位有符号整数的 byte[] 需要 2GB 的连续地址空间。您不应该尝试创建这样的数组。否则,如果大小不是真的那么大(而且它只是一个更大的类型),您可以安全地将其转换为 int 并使用它来创建数组。

    【讨论】:

    • 最初的提问者大概没有使用 32 位 JVM。可以构造一个 2^32 字节的 int[] 数组...
    • 实际上最大值是 31 位整数,因为 java 的类型是有符号的。所以大概是 2 场演出。
    • jbu:哎呀。你说得对。显然,它也可以在 64 位进程中使用,但我的意思是它太大了,如果你真的要创建这么大的数组,你很可能走错了路。
    • mehrdad:我不知道 是不是走错路了……再说一次,我正在处理的消息类型可能那么大(理论上)。似乎走错路的是创建此消息类型的人。我不知道他是否使用了他的消息的完整大小,但我觉得我想支持他的消息而不是丢弃字节(即使他使用它们)。
    • 如果您真的希望消息有那么大,您应该使用某种缓冲机制,这样您就不会一次将整个消息加载到内存中。我刚刚尝试在 64 位 JVM 中创建一个 2^30 字节(Integer.MAX_VALUE/2)的数组,它抛出 OutOfMemoryError。
    【解决方案3】:

    您可能应该使用一个流来读取您的数据,并使用另一个流来将其写出。如果您以后需要访问文件中的数据,请保存它。如果您需要访问尚未遇到的东西,则需要一个双通道系统,您可以在其中运行一次并存储“第二次运行所需的东西,然后再次运行”。

    编译器就是这样工作的。

    一次加载整个数组的唯一情况是您必须反复随机访问整个数组的许多位置。如果是这种情况,我建议您将其加载到多个字节数组中,所有这些字节数组都存储在一个容器类中。

    容器类将有一个字节数组数组,但从外部来看,所有访问似乎都是连续的。您只需请求字节 49874329128714391837,您的班级会将您的 Long 除以每个字节数组的大小以计算要访问的数组,然后使用余数来确定字节。

    它还可以具有存储和检索“块”的方法,这些“块”可以跨越需要​​创建临时副本的字节数组边界——但创建一些临时数组的成本将远远超过这一事实您没有分配锁定的 2gb 空间,我认为这可能会破坏您的性能。

    编辑:ps。如果你真的需要随机访问并且不能使用流,那么实现一个包含类是一个非常好的主意。它可以让您将实现从单个字节数组动态更改为一组字节数组,再到基于文件的系统,而无需对其余代码进行任何更改。

    【讨论】:

    • 我怀疑即使在那种情况下你也能分配这么多的内存。让long 单独,第二行在我的机器上的 64 位 JRE 上引发异常:“byte[] a1 = new byte[Integer.MAX_VALUE/4]; byte[] a2 = new byte[Integer.MAX_VALUE/4] ;"如果他要处理如此大量的数据,他将不得不使用某种内存缓冲区。
    • 这就是为什么我建议使用一个小类来即时更改实现。当然,如果可能的话,应该使用流式传输(而且绝对应该是可能的!),但如果没有,也可以使用某种缓存算法,其中包含由软引用保存的较小块。
    【解决方案4】:

    这不是立竿见影的帮助,但创建更大尺寸的数组(通过 longs)是 Java 7 的一项拟议语言更改。查看 Project Coin 提案以获取更多信息

    【解决方案5】:

    “存储”数组的一种方法是将其写入文件,然后使用 RandomAccessFile 访问它(如果您需要像访问数组一样访问它)。该文件的 api 使用 long 作为文件的索引而不是 int。它会更慢,但对内存的负担要小得多。

    这是您在初始输入扫描期间无法提取所需内容的情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-23
      • 2012-07-14
      • 2017-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-18
      相关资源
      最近更新 更多