【问题标题】:Max capacity of String array字符串数组的最大容量
【发布时间】:2020-06-27 07:39:17
【问题描述】:

我得到单个记录,其中包含多个子记录,由 , 分隔

任何单个子记录的大小为200 个字符,子记录的数量可以达到 500 万条记录。

将所有记录存储在字符串数组中是一种好习惯吗?它会引起任何问题吗?如果是,我怎样才能以有效的方式执行?磁盘内存充足。

inpString.split(,);

来源给我一个记录,在 Active Directory 中包含所有用户信息。

更新

这是带有 2 个子记录的输入示例字符串(每个子记录中的字符都较少,仅作为示例)。最大可达5M

CN=100,OU=Employee,OU=groups,DC=AD,DC=myhost;CN=200,OU=Employee,OU=groups,DC=AD,DC=myhost;

在文件中输出

batchID,groupName,ou=groupapplicationname,CN=100,uid=100,DC=AD,DC=myhost,moreinfo
batchID,groupName,ou=groupapplicationname,CN=200,uid=100,DC=AD,DC=myhost,moreinfo

【问题讨论】:

  • 程序运行时,它使用主内存,而不是辅助存储。
  • @PalLaden,所以你的意思是,不会有问题?

标签: java arrays memory-management


【解决方案1】:

理论上,一个 Java 字符串可以包含接近 2^31 个字符,一个 Java 数组可以包含接近 2^31 个字符串。

在实践中(假设Java 8,64位,没有oops1String[]String的空间利用率如下:

  • String[] 数组每个条目需要 8 个字节,
  • String 每个字符需要 2 个字节...加上每个 String 大约 40 个字节的开销。

很容易看出,与 64 位地址可寻址相比,最大大小的字符串的最大数组将占用更多的内存,即使假设您可以构建一台能够容纳这么多内存的机器。然而,这只是一个理论上的问题......

在你的例子中:

我的猜测是,表示数组和字符串所需的空间大约为 500 x 5,000,000 = 2.5GB 堆空间。如果您在拆分之前先将整个记录以String 的形式读入内存,则可能高达 7.5GB,具体取决于您读取它的方式。 (但你可以比这更聪明......)


将所有记录存储在字符串数组中是一种好习惯吗?

这取决于您打算如何处理这些记录。没有更多信息,我们不能说这是否是一个好主意。

请注意,没有一般意义上的“良好做法”或“最佳做法”。解决方案需要有针对性地设计,并且只能在上下文中做出判断。

会有什么问题吗?

如上所述,它可能会使用大量堆空间。

如果是,我怎样才能有效地执行?

除非您清楚地解释您实际上将如何处理内存中的记录,否则我们无法告诉您。

这也取决于你关心什么样的效率。 CPU利用率?内存利用率?软件开发时间?

磁盘内存充足。

这可能相关,也可能不相关。这取决于您要如何处理内存中的记录。

1 - 用于表示字符串的空间量在许多方面取决于 JVM。例如,从 Java 9 开始,由 ASCII 字符组成的字符串每个字符只需要 1 个字节。


所以看看你更新的问题,很明显将整个文件读入内存并拆分它是错误的方法。

您需要做的是读取字符,直到获得记录;即直到您收到;。然后根据, 将记录拆分为字段。然后您处理这些字段并输出它们。最后你丢弃那条记录并开始阅读下一条。

换句话说,您可以避免在内存中创建一个包含 5,000,000 个字符串的巨大数组。

【讨论】:

  • 我将从子记录中提取字段 + 对字段进行一些修改并将其写入文件。子记录数等于输出文件中的记录数。
  • 那么你用字符串数组做什么?为什么你需要它?
  • 需要从子记录中提取一些字段并放入新模式并将该记录写入文件。你会如何建议..?
  • 可能值得注意的是,字符串处理完全依赖于实现,并且在存储字符串方面已经有了显着的改进since Java 9
  • 是的。虽然在这个特定的例子中,OP 不需要/不应该首先使用一个大的字符串数组。
【解决方案2】:

编写了一个程序,该程序创建了一个包含 500 万个字符串的数组,并用一个包含 200 个字符的数组来初始化它们。 (Scanner 是暂停 程序,我去看看内存)。

import java.util.Scanner;
public class ArrMem
{
    public static void main(String args[])
    {
        String[] s = new String[5000000];
        for(int i=0;i<5000000;i++)
        {
            s[i] = new String(new char[200]);
        }
        Scanner sc = new Scanner(System.in);
        sc.nextLine();
    }
}

并执行了它。使用的 RAM 如下所示。

考虑到您不会一次处理所有字符串,您应该从文件中分批提取它们(以减少与文件系统的交互)并处理它们。这是你想要坚持自己的方法的时候。

Batch Size Execution Time Memory Used
Larger Lower Higher
Smaller Higher Lower

或者

使用BufferedReader() 从文件中读取子记录。

【讨论】:

    猜你喜欢
    • 2020-01-10
    • 2012-01-17
    • 1970-01-01
    • 1970-01-01
    • 2017-09-06
    • 1970-01-01
    • 1970-01-01
    • 2019-11-21
    • 2019-04-11
    相关资源
    最近更新 更多