Độ dài tối đa có thể có của một chuỗi .NET là bao nhiêu?


239

Chuỗi dài nhất có thể được tạo trong .NET là gì? Các tài liệu cho Stringlớp học im lặng về câu hỏi này theo như tôi có thể thấy, vì vậy một câu trả lời có thẩm quyền có thể yêu cầu một số kiến ​​thức về nội bộ. Thay đổi tối đa trên hệ thống 64 bit?

[Điều này được hỏi nhiều hơn vì sự tò mò hơn là sử dụng thực tế - Tôi không có ý định tạo bất kỳ mã nào sử dụng chuỗi khổng lồ!]

Câu trả lời:


345

Giới hạn lý thuyết có thể là 2.147.483.647, nhưng giới hạn thực tế không ở đâu gần đó. Vì không có đối tượng nào trong chương trình .NET có thể có trên 2GB và loại chuỗi sử dụng UTF-16 (2 byte cho mỗi ký tự), điều tốt nhất bạn có thể làm là 1.073.741.823, nhưng bạn không có khả năng phân bổ điều đó trên máy 32 bit.

Đây là một trong những tình huống trong đó "Nếu bạn phải hỏi, có lẽ bạn đã làm sai điều gì đó."


8
Đây là câu trả lời chính xác. Bạn có nhiều khả năng hết bộ nhớ trước khi có thể phân bổ đủ để làm cạn kiệt độ dài chuỗi. Trên một khởi động mới, bạn có thể có thể phân bổ 2GB (với 1 triệu ký tự) như đã đề cập ở đây, nhưng chỉ vậy thôi.
Stephen Deken

4
Giả sử rằng khẳng định "không có đối tượng đơn lẻ nào có thể vượt quá 2Gb" là chính xác, đây là giới hạn lý thuyết cũng như giới hạn thực tế - ràng buộc về độ dài Chuỗi sẽ là tổng kích thước đối tượng, không phải là dung lượng của trường Độ dài.
McKenzieG1

12
Nếu bất cứ ai quan tâm đến giá trị chính xác, trên máy 64 bit của tôi, đó là 1.073.741.791 (1024 · 1024 · 1024 - 33) ký tự. Xem thêm câu hỏi liên quan của tôi về kích thước tối đa chính xác củabyte[] .
Svick

4
Tôi phát điên về những câu trả lời có chứa lời giải thích ngắn gọn nhưng sâu sắc.
Mikayil Abdullayev

3
Có một tùy chọn để cho phép các đối tượng .NET 4.5 (và mới hơn) lớn hơn 2GB trên các máy 64 bit. Kiểm tra tại đây
Anderson Matos

72

Dựa trên thử nghiệm rất khoa học và chính xác của tôi, nó xuất hiện trên máy của tôi trước 1.000.000.000 ký tự. (Tôi vẫn đang chạy mã bên dưới để có được xác định chính xác hơn).

CẬP NHẬT: Sau một vài giờ, tôi đã bỏ cuộc. Kết quả cuối cùng: Có thể lớn hơn rất nhiều hơn 100.000.000 ký tự, được đưa ra ngay lập tức System.OutOfMemoryExceptionở mức 1.000.000.000 ký tự.

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
}

35
Áp dụng tìm kiếm nhị phân ở đây có thể sẽ giúp bạn tìm thấy câu trả lời này nhanh hơn rất nhiều ...
Mario

49

Vì thuộc Lengthtính của System.Stringlà một Int32, tôi đoán rằng độ dài tối đa sẽ là 2.147.483.647 ký tự ( Int32kích thước tối đa ). Nếu nó cho phép lâu hơn, bạn không thể kiểm tra Độ dài vì điều đó sẽ thất bại.


2
@ m.edmondson: Tôi thực sự không bị thuyết phục. Một mảng cho các trường hợp cũng có LongLengthmột luồng và một luồng sử dụng longnhư chiều dài. Mặc dù đó là câu trả lời hợp lệ, nhưng đây không phải là cách chính xác để đo lường điều này.
Willem Van Onsem

1
Nhưng hai bit đầu tiên được sử dụng cho chỉ thị ASCII / không phải ASCII như bài viết này nói, vì vậy nó phải là 2 ^ 30 = 1 073 741 824
Saito

28

Đối với bất kỳ ai đến chủ đề này muộn, tôi có thể thấy rằng "bạn có thể không nên làm điều đó" có thể khiến ai đó hỏi họ nên làm gì

Lớp StringBuilder thường là một sự thay thế dễ dàng. Đặc biệt xem xét một trong các lớp dựa trên luồng , nếu dữ liệu của bạn đến từ một tệp.

Vấn đề với s += "stuff"là nó phải phân bổ một khu vực hoàn toàn mới để chứa dữ liệu và sau đó sao chép tất cả dữ liệu cũ sang dữ liệu mới - MACHI VÀ MỌI THỨ KHIẾU NẠI. Vì vậy, việc thêm năm byte vào 1.000.000 với s += "stuff"cực kỳ tốn kém. Nếu điều bạn muốn là chỉ cần viết năm byte đến cuối và tiếp tục với chương trình của bạn, bạn phải chọn một lớp để lại một số chỗ cho sự phát triển:

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

StringBuildersẽ tự động phát triển bằng cách nhân đôi khi giới hạn của nó bị tấn công. Vì vậy, bạn sẽ thấy cơn đau tăng trưởng một lần khi bắt đầu, một lần ở mức 5.000 byte, một lần nữa ở mức 10.000, một lần nữa ở mức 20.000. Nối các chuỗi sẽ phát sinh cơn đau mỗi lần lặp.


4
Điều đáng chú ý là StringBuilder cho phép bạn đặt kích thước ban đầu. Hữu ích nếu bạn biết rằng bạn sẽ sử dụng 10.000.000 mục trước thời hạn, cho phép bạn bỏ qua một số khủng hoảng.
Kyle Baran

3
+1 Để xem qua câu hỏi và trả lời thiết kế tốt. Một cách tương đối, "đây là chuỗi của bạn có thể lớn như thế nào trước khi nó thổi", trái ngược với "nếu bạn THỰC SỰ cần lưu trữ nhiều văn bản, hãy sử dụng ..."
StevoInco

8

Độ dài tối đa của một chuỗi trên máy của tôi1.073.741.791 .

Bạn thấy đấy, Chuỗi không bị giới hạn bởi số nguyên như thường được tin.

Bỏ qua các hạn chế về bộ nhớ, Chuỗi không thể có nhiều hơn 2 30 ( 1.073.741.824 ) ký tự, do giới hạn 2GB được áp dụng bởi Microsoft CLR (Thời gian chạy ngôn ngữ chung). Hơn 33 máy tính của tôi cho phép.

Bây giờ, đây là một cái gì đó bạn có thể tự mình thử.

Tạo một ứng dụng bảng điều khiển C # mới trong Visual Studio và sau đó sao chép / dán phương thức chính tại đây:

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();

}

Kết quả của tôi như sau:

Kiểm tra chuỗi, bởi Nicholas John Joseph Taylor

Về mặt lý thuyết, C # nên hỗ trợ một chuỗi int.MaxValue, nhưng trước đó chúng tôi đã hết bộ nhớ.

Đây là một thử nghiệm nhanh để thu hẹp kết quả để tìm độ dài tối đa được hỗ trợ của chuỗi.

Bài kiểm tra bắt đầu ... ngay bây giờ:

s.Lipse = 1000000000 lúc 08/05/2019 12:06

Ngoại lệ của loại 'System.OutOfMemoryException' đã được ném. lúc 08/05/2019 12:06. Sau khi giảm, giá trị của Tăng là 100000000.

Ngoại lệ của loại 'System.OutOfMemoryException' đã được ném. lúc 08/05/2019 12:06. Sau khi giảm giá trị, giá trị của Tăng là 10000000. s.Lipse = 1010000000 vào ngày 08/05/2019 12:06 s. Chiều dài = 1020000000 lúc 08/05/2019 12:06 s.Lipse = 1030000000 lúc 08/05/2019 12 : 06 s. Chiều dài = 1040000000 lúc 08/05/2019 12:06 s. Chiều dài = 1050000000 lúc 08/05/2019 12:06 s. Chiều dài = 1060000000 lúc 08/05/2019 12:06 s.Lạng = 1070000000 tại 08/05/2019 12:06

Ngoại lệ của loại 'System.OutOfMemoryException' đã được ném. lúc 08/05/2019 12:06. Sau khi giảm giá trị, giá trị của Tăng là 1000000. s.Lipse = 1071000000 lúc 08/05/2019 12:06 s.Lipse = 1072000000 lúc 08/05/2019 12:06 s.Lipse = 1073000000 lúc 08/05/2019 12 : 06

Ngoại lệ của loại 'System.OutOfMemoryException' đã được ném. lúc 08/05/2019 12:06. Sau khi giảm giá trị, giá trị của Tăng là 100000. s.Lipse = 1073100000 lúc 08/05/2019 12:06 s.Lipse = 1073200000 lúc 08/05/2019 12:06 s.Lipse = 1073300000 lúc 08/05/2019 12 : 06 s.Lpm = 1073400000 lúc 08/05/2019 12:06 s.Lipse = 1073500000 lúc 08/05/2019 12:06 s.Lipse = 1073600000 lúc 08/05/2019 12:06 s.Lipse = 1073700000 tại 08/05/2019 12:06

Ngoại lệ của loại 'System.OutOfMemoryException' đã được ném. lúc 08/05/2019 12:06. Sau khi giảm giá trị, giá trị của Tăng là 10000. s. Chiều dài = 1073710000 lúc 08/05/2019 12:06 s. Chiều dài = 1073720000 lúc 08/05/2019 12:06 s. Chiều dài = 1073730000 lúc 08/05/2019 12 : 06 s. Chiều dài = 1073740000 lúc 08/05/2019 12:06

Ngoại lệ của loại 'System.OutOfMemoryException' đã được ném. lúc 08/05/2019 12:06. Sau khi giảm giá trị, giá trị của Tăng là 1000. s.Lipse = 1073741000 vào ngày 08/05/2019 12:06

Ngoại lệ của loại 'System.OutOfMemoryException' đã được ném. lúc 08/05/2019 12:06. Sau khi giảm giá trị, giá trị của Tăng là 100. s.Lipse = 1073741100 lúc 08/05/2019 12:06 s. : 07 s. Chiều dài = 1073741400 lúc 08/05/2019 12:07 s. Chiều dài = 1073741500 lúc 08/05/2019 12:07 s. 08/05/2019 12:07

Ngoại lệ của loại 'System.OutOfMemoryException' đã được ném. lúc 08/05/2019 12:07. Sau khi giảm giá trị, giá trị của Tăng là 10. s.Lipse = 1073741710 lúc 08/05/2019 12:07 s. : 07 s. Chiều dài = 1073741740 lúc 08/05/2019 12:07 s. Chiều dài = 1073741750 lúc 08/05/2019 12:07 s. 08/05/2019 12:07 s. Chiều dài = 1073741780 lúc 08/05/2019 12:07 s. Chiều dài = 1073741790 lúc 08/05/2019 12:07

Ngoại lệ của loại 'System.OutOfMemoryException' đã được ném. lúc 08/05/2019 12:07. Sau khi giảm giá trị, giá trị của Tăng là 1. s.Lipse = 1073741791 lúc 08/05/2019 12:07

Ngoại lệ của loại 'System.OutOfMemoryException' đã được ném. lúc 08/05/2019 12:07. Sau khi giảm, giá trị của Tăng là 0. Kiểm tra hoàn tất.

Độ dài tối đa của một chuỗi là 1073741791.

Bấm phím bất kỳ để tiếp tục.

Độ dài tối đa của một chuỗi trên máy của tôi là 1073741791.

Tôi đánh giá cao nó rất nhiều nếu mọi người có thể đăng kết quả của họ như một bình luận bên dưới.

Sẽ rất thú vị khi tìm hiểu nếu mọi người nhận được kết quả giống nhau hoặc khác nhau.


"Bạn thấy đấy, Chuỗi không bị giới hạn bởi số nguyên như thường được tin." -> một số nguyên trong c # có thể lên tới 2.147.483.647 và kết quả của bạn rất gần (giảm 32 byte) với giá trị này chia cho hai, điều này hợp lý vì mọi ký tự của Chuỗi được lưu dưới dạng Unicode trên hai byte. Vì vậy, ngay cả khi giới hạn không bị áp đặt bởi kích thước của số nguyên, nó vẫn gần với giới hạn đó.
Ben

2

200 megs ... tại thời điểm đó, ứng dụng của bạn dừng hoạt động ảo, có bộ nhớ hoạt động rất lớn và o / s bắt đầu hoạt động như bạn sẽ cần phải khởi động lại.

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

5
Tôi không chắc hành vi bạn nhận được từ việc tạo ra một chuỗi thực sự lớn giống như những gì bạn đang thấy bằng cách phân bổ một loạt chúng và nối.
Casey

1

String.Lengthlà một số nguyên (đó là bí danh cho Int32), kích thước của nó được giới hạn ở các Int32.MaxValueký tự unicode. ;-)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.