【问题标题】:What is the maximum possible length of a .NET string?.NET 字符串的最大可能长度是多少?
【发布时间】:2010-09-13 12:26:35
【问题描述】:

.NET 中可以创建的最长字符串是多少?据我所知,String 类的文档对这个问题保持沉默,因此权威答案可能需要一些内部知识。 64 位系统上的最大值会改变吗?

[更多的是出于好奇而不是实际使用-我不打算创建任何使用巨大字符串的代码!]

【问题讨论】:

    标签: .net string limits


    【解决方案1】:

    理论极限可能是 2,147,483,647,但实际极限远不及此。由于 .NET 程序中没有单个对象可能超过 2GB,并且字符串类型使用 UTF-16(每个字符 2 个字节),因此您可以做的最好的事情是 1,073,741,823,但您不太可能能够分配它在 32 位机器上。

    这是"If you have to ask, you're probably doing something wrong." 的情况之一

    【讨论】:

    • 这是正确答案。在能够分配足够的字符串长度之前,您更有可能耗尽内存。在全新启动时,您可能能够提取此处提到的 2GB(包含 1M 个字符)的分配,但仅此而已。
    • 假设您的“没有单个对象可能超过 2Gb”的断言是准确的,这是理论限制以及实际限制 - 对字符串长度的限制将是总对象大小,而不是Length 字段的容量。
    • 如果有人对确切值感兴趣,在我的 64 位机器上它是 1,073,741,791 (1024 · 1024 · 1024 - 33) 个字符。另请参阅my related question about the exact max size of byte[]
    • 我对包含简短但深入解释的答案感到疯狂。
    • 有一个选项允许 .NET 4.5(及更高版本)对象在 64 位计算机上大于 2GB。 Check here
    【解决方案2】:

    根据我的高度科学和准确的实验,它在我的机器上早在 1,000,000,000 个字符之前就已达到顶峰。 (我仍在运行下面的代码以获得更好的精确定位)。

    更新: 几个小时后,我放弃了。最终结果:可以超过 100,000,000 个字符,立即给出 System.OutOfMemoryException 1,000,000,000 个字符。

    using System;
    using System.Collections.Generic;
    
    public class MyClass
    {
        public static void Main()
        {
            int i = 100000000;
            try
            {
                for (i = i; i <= int.MaxValue; i += 5000)
                {
                    string value = new string('x', i);
                    //WL(i);
                }
            }
            catch (Exception exc)
            {
                WL(i);
                WL(exc);
            }
            WL(i);
            RL();
        }
    
        #region Helper methods
    
        private static void WL(object text, params object[] args)
        {
            Console.WriteLine(text.ToString(), args);   
        }
    
        private static void RL()
        {
            Console.ReadLine(); 
        }
    
        private static void Break() 
        {
            System.Diagnostics.Debugger.Break();
        }
    
        #endregion
    }
    

    【讨论】:

    • 在这里应用二进制搜索可能会帮助您更快地找到这个答案......
    【解决方案3】:

    由于System.StringLength 属性是Int32,我猜最大长度为2,147,483,647 个字符(最大Int32 大小)。如果它允许更长的时间,您将无法检查长度,因为那会失败。

    【讨论】:

    • @m.edmondson:实际上我并不相信。实例的array 也有LongLength,流使用long 作为长度。虽然它是有效的答案,但它不是衡量这一点的准确方法。
    • 但正如this article所说,前两位用于ASCII/非ASCII指示,所以它应该是2^30 = 1 073 741 824
    【解决方案4】:

    对于迟到的人来说,我可以看到即时扫描的“你可能不应该这样做”可能会导致有人问他们应该做什么......

    StringBuilder 类通常很容易替换。 如果您的数据来自文件,请特别考虑stream-based classes 之一。

    s += "stuff" 的问题在于它必须分配一个全新的区域来保存数据,然后将所有旧数据以及新内容复制到其中 - 每个和每个循环迭代。因此,使用s += "stuff" 将五个字节添加到 1,000,000 是非常昂贵的。 如果你想要的只是写五个字节到最后并继续你的程序,你必须选择一个留下一些增长空间的类:

    StringBuilder sb = new StringBuilder(5000);
    for (; ; )
        {
            sb.Append("stuff");
        }
    

    StringBuilder 将在达到限制时auto-grow by doubling。因此,您将在开始时看到一次增长的痛苦,一次是 5,000 字节,再次是 10,000 字节,再次是 20,000 字节。附加字符串会在每次循环迭代时产生痛苦。

    【讨论】:

    • 另外值得注意的是,StringBuilder 允许您设置初始大小。如果您知道您将提前使用 10,000,000 个条目,这很有用,可以让您忽略一些紧缩。
    • +1 用于看透问题并回答好的设计。相比之下,“这是你的弦在爆炸之前可以有多大”,而不是“如果你真的需要存储大量文本,请使用这个......”
    【解决方案5】:

    字符串的最大长度在我的机器上1,073,741,791

    你看,字符串并不像通常认为的那样受整数限制。

    除了内存限制,字符串不能超过 230 (1,073,741,824) 个字符,因为 Microsoft CLR(公共语言运行时)规定了 2GB 的限制。比我的电脑允许的多 33 个。

    现在,欢迎您自己尝试一下。

    在 Visual Studio 中创建一个新的 C# 控制台应用,然后在此处复制/粘贴 main 方法:

    static void Main(string[] args)
    {
        Console.WriteLine("String test, by Nicholas John Joseph Taylor");
    
        Console.WriteLine("\nTheoretically, C# should support a string of int.MaxValue, but we run out of memory before then.");
    
        Console.WriteLine("\nThis is a quickish test to narrow down results to find the max supported length of a string.");
    
        Console.WriteLine("\nThe test starts ...now:\n");
    
        int Length = 0;
    
        string s = "";
    
        int Increment = 1000000000; // We know that s string with the length of 1000000000 causes an out of memory exception.
    
        LoopPoint:
    
        // Make a string appendage the length of the value of Increment
    
        StringBuilder StringAppendage = new StringBuilder();
    
        for (int CharacterPosition = 0; CharacterPosition < Increment; CharacterPosition++)
        {
            StringAppendage.Append("0");
    
        }
    
        // Repeatedly append string appendage until an out of memory exception is thrown.
    
        try
        {
            if (Increment > 0)
                while (Length < int.MaxValue)
                {
                    Length += Increment;
    
                    s += StringAppendage.ToString(); // Append string appendage the length of the value of Increment
    
                    Console.WriteLine("s.Length = " + s.Length + " at " + DateTime.Now.ToString("dd/MM/yyyy HH:mm"));
    
                }
    
        }
        catch (OutOfMemoryException ex) // Note: Any other exception will crash the program.
        {
            Console.WriteLine("\n" + ex.Message + " at " + DateTime.Now.ToString("dd/MM/yyyy HH:mm") + ".");
    
            Length -= Increment;
    
            Increment /= 10;
    
            Console.WriteLine("After decimation, the value of Increment is " + Increment + ".");
    
        }
        catch (Exception ex2)
        {
            Console.WriteLine("\n" + ex2.Message + " at " + DateTime.Now.ToString("dd/MM/yyyy HH:mm") + ".");
    
            Console.WriteLine("Press a key to continue...");
    
            Console.ReadKey();
    
        }
    
        if (Increment > 0)
        {
            goto LoopPoint;
    
        }
    
        Console.WriteLine("Test complete.");
    
        Console.WriteLine("\nThe max length of a string is " + s.Length + ".");
    
        Console.WriteLine("\nPress any key to continue.");
    
        Console.ReadKey();
    
    }
    

    我的结果如下:

    弦乐测试,尼古拉斯·约翰·约瑟夫·泰勒 (Nicholas John Joseph Taylor) 着

    理论上,C#应该支持int.MaxValue的字符串,但是我们运行 在那之前内存不足。

    这是一个快速测试,可缩小结果范围以找到最大值 支持的字符串长度。

    测试开始……现在:

    s.Length = 1000000000 在 08/05/2019 12:06

    引发了“System.OutOfMemoryException”类型的异常。在 2019 年 8 月 5 日 12:06。抽取后,Increment 的值为 100000000。

    引发了“System.OutOfMemoryException”类型的异常。在 2019 年 8 月 5 日 12:06。抽取后,Increment 的值为 10000000.s.Length = 1010000000 在 08/05/2019 12:06 s.Length = 1020000000 在 08/05/2019 12:06 s.Length = 1030000000 在 08/05/2019 12:06 秒长度 = 1040000000 在 2019 年 8 月 5 日 12:06 秒长度 = 1050000000 2019 年 8 月 5 日 12:06 秒长度 = 1060000000 2019 年 8 月 5 日 12:06 秒长度 = 1070000000 在 08/05/2019 12:06

    引发了“System.OutOfMemoryException”类型的异常。在 2019 年 8 月 5 日 12:06。抽取后,Increment 的值为 1000000。 s.Length = 1071000000 在 08/05/2019 12:06 s.Length = 1072000000 在 08/05/2019 12:06 s.Length = 1073000000 在 08/05/2019 12:06

    引发了“System.OutOfMemoryException”类型的异常。在 2019 年 8 月 5 日 12:06。抽取后,Increment 的值为 100000。 s.Length = 1073100000 在 08/05/2019 12:06 s.Length = 1073200000 在 2019 年 8 月 5 日 12:06 秒长度 = 1073300000 在 2019 年 8 月 5 日 12:06 秒长度 = 1073400000 2019 年 8 月 5 日 12:06 秒长度 = 1073500000 2019 年 8 月 5 日 12:06 秒长度 = 1073600000 在 2019 年 8 月 5 日 12:06 秒长度 = 1073700000 在 08/05/2019 12:06

    引发了“System.OutOfMemoryException”类型的异常。在 2019 年 8 月 5 日 12:06。抽取后,Increment 的值为 10000。 s.Length = 1073710000 在 08/05/2019 12:06 s.Length = 1073720000 在 2019 年 8 月 5 日 12:06 秒长度 = 1073730000 在 2019 年 8 月 5 日 12:06 秒长度 = 1073740000 在 08/05/2019 12:06

    引发了“System.OutOfMemoryException”类型的异常。在 2019 年 8 月 5 日 12:06。抽取后,Increment 的值为 1000。 s.Length = 1073741000 在 08/05/2019 12:06

    引发了“System.OutOfMemoryException”类型的异常。在 2019 年 8 月 5 日 12:06。抽取后,Increment 的值为 100。 s.Length = 1073741100 在 08/05/2019 12:06 s.Length = 1073741200 在 2019 年 8 月 5 日 12:06 秒长度 = 1073741300 在 2019 年 8 月 5 日 12:07 秒长度 = 1073741400 2019 年 8 月 5 日 12:07 秒长度 = 1073741500 2019 年 8 月 5 日 12:07 秒长度 = 1073741600 在 2019 年 8 月 5 日 12:07 秒长度 = 1073741700 在 08/05/2019 12:07

    引发了“System.OutOfMemoryException”类型的异常。在 2019 年 8 月 5 日 12:07。抽取后,Increment 的值为 10。 s.Length = 1073741710 在 08/05/2019 12:07 s.Length = 1073741720 在 2019 年 8 月 5 日 12:07 秒长度 = 1073741730 2019 年 8 月 5 日 12:07 秒长度 = 1073741740 2019 年 8 月 5 日 12:07 秒长度 = 1073741750 2019 年 8 月 5 日 12:07 秒长度 = 1073741760 在 2019 年 8 月 5 日 12:07 秒长度 = 1073741770 2019 年 8 月 5 日 12:07 秒长度 = 1073741780 2019 年 8 月 5 日 12:07 秒长度 = 1073741790 在 08/05/2019 12:07

    引发了“System.OutOfMemoryException”类型的异常。在 2019 年 8 月 5 日 12:07。抽取后,Increment 的值为 1。 s.Length = 1073741791 在 08/05/2019 12:07

    引发了“System.OutOfMemoryException”类型的异常。在 2019 年 8 月 5 日 12:07。抽取后,Increment 的值为 0。测试 完成。

    字符串的最大长度为 1073741791。

    按任意键继续。

    我机器上字符串的最大长度是1073741791。

    如果人们可以将他们的结果作为评论发布在下面,我将非常感激。

    了解人们是否得到相同或不同的结果会很有趣。

    【讨论】:

    • “你看,字符串并不像通常认为的那样受整数限制。” --> c# 中的整数可以达到 2,147,483,647,您的结果非常接近(少 32 个字节)除以二的值,这是合乎逻辑的,因为字符串的每个字符都以 Unicode 形式存储在两个字节上。所以即使限制不是由整数的大小强加的,它也非常接近它。
    • 感谢您的代码。我设法在带有 ARM M1、.net 3.1 的 OSX 上重现它:字符串的最大长度为 1073741791。
    【解决方案6】:

    由于String.Length 是一个整数(即Int32 的别名),它的大小限制为Int32.MaxValue Unicode 字符。 ;-)

    【讨论】:

      【解决方案7】:

      200 megs...此时您的应用程序几乎停止运行,大约有一个 gig 工作集内存,并且操作系统开始运行,就像您需要重新启动一样。

      static void Main(string[] args)
      {
          string s = "hello world";
          for(;;)
          {
              s = s + s.Substring(0, s.Length/10);
              Console.WriteLine(s.Length);
          }
      }
      
      12
      13
      14
      15
      16
      17
      18
      ...
      158905664
      174796230
      192275853
      211503438
      

      【讨论】:

      • 我不确定你从创建一个非常大的字符串得到的行为是否与你通过分配一堆并连接所看到的行为相同。
      【解决方案8】:

      String 在您的 RAM 堆中分配动态内存大小。但是字符串地址存储在堆栈中,占用4个字节的内存。

      【讨论】:

        猜你喜欢
        • 2010-10-23
        • 2010-12-16
        • 2011-12-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-19
        • 2016-09-11
        相关资源
        最近更新 更多