.NET dizesinin olası maksimum uzunluğu nedir?


239

.NET ile oluşturulabilecek en uzun dize nedir? StringSınıf için dokümanlar görebildiğim kadarıyla bu soruya sessiz, bu yüzden yetkili bir cevap içsel bilgi biraz gerektirebilir. 64 bit sistemde maksimum değişiklik olur mu?

[Bu pratik kullanımdan daha fazla merak için sorulur - Devasa dizeler kullanan herhangi bir kod oluşturmak niyetinde değilim!]

Yanıtlar:


346

Teorik sınır 2.147.483.647 olabilir, ancak pratik sınır bunun yakınında değildir. Bir .NET programındaki hiçbir nesne 2 GB üzerinde olamaz ve dize türü UTF-16 (her karakter için 2 bayt) kullandığından, yapabileceğiniz en iyi şey 1.073.741.823'tür, ancak bunu ayıramazsınız. 32 bit makinede.

Bu, "Sormanız gerekiyorsa, muhtemelen yanlış bir şey yapıyorsunuz" durumlarından biridir .


8
Bu doğru cevap. Dize uzunluğunu tüketmek için yeterli ayırma yapmadan önce hafızanızın bitmesi daha olasıdır. Yeni bir önyüklemede, burada belirtildiği gibi 2GB (1M karakterlerle) ayırmayı çekebilirsiniz, ancak hepsi bu.
Stephen Deken

4
"Tek bir nesnenin 2 Gb üzerinde olamaz" iddiasının doğru olduğunu varsayarsak, bu teorik sınırın yanı sıra pratik olan IS'dir - String uzunluğundaki kısıtlama, Uzunluk alanının kapasitesi değil, toplam nesne boyutu olacaktır.
McKenzieG1

12
Kesin değerle ilgilenen varsa, 64 bit makinemde 1.073.741.791 (1024 · 1024 · 1024 - 33) karakter var. Ayrıca tam maksimum boyutu hakkında ilgili sorumabyte[] bakın .
svick

4
Kısa ama derinlemesine açıklamalar içeren cevaplar için deliriyorum.
Mikayil Abdullayev

3
64-bit makinelerde .NET 4.5 (ve üstü) nesnelerinin 2 GB'den büyük olmasına izin verme seçeneği vardır. Buradan kontrol edin
Anderson Matos

72

Son derece bilimsel ve doğru denemelerime dayanarak, 1.000.000.000 karakterden çok önce makinemde öne çıkıyor. (Daha iyi bir noktaya ulaşmak için hala aşağıdaki kodu çalıştırıyorum).

GÜNCELLEME: Birkaç saat sonra vazgeçtim. Nihai sonuçlar: Anında System.OutOfMemoryException1.000.000.000 karakterle verilen 100.000.000 karakterden çok daha büyük olabilir .

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
Burada bir ikili arama uygulamak muhtemelen bu cevabı çok daha hızlı bulmanıza yardımcı olacaktır ...
Mario

49

Yana Lengthmalı System.Stringbir olan Int32, bir maksimum uzunluk 2,147,483,647 karakter (maks olacağını tahmin ediyorum Int32boyutu). Daha uzun süre izin verdiyse, bu başarısız olacağından Uzunluğu kontrol edemezdiniz.


2
@ m.edmondson: Aslında ikna olmadım. Örnekler için bir diziLongLength de içerir ve bir akış longuzunluk olarak kullanır . Geçerli bir cevap olmasına rağmen, bunu ölçmenin doğru bir yolu yoktur.
Willem Van Onsem

1
Ancak ilk iki bit, bu makalede belirtildiği gibi ASCII / ASCII dışı endikasyon için kullanılır , bu yüzden 2 ^ 30 = 1 073 741 824
Saito

28

Bu konuya geç gelen herkes için, hitscan'ın "muhtemelen bunu yapmamalısın" birisinin ne yapması gerektiğini sormasına neden olabileceğini görebiliyordum ...

StringBuilder sınıfı genellikle kolay bir yerine geçer. Akış tabanlı sınıflardan birini düşününÖzellikle verileriniz bir dosyadan geliyorsa .

Sorun s += "stuff"şu ki, verileri tutmak için tamamen yeni bir alan tahsis etmek ve daha sonra tüm eski verileri artı yeni şeyleri kopyalamak zorunda - HER VE HER DÖNGÜ TESPİTİ. Bu nedenle, 1.000.000'a beş bayt eklemek s += "stuff"son derece maliyetlidir. İstediğiniz şey sonuna beş bayt yazmak ve programınıza devam etmekse, büyümeye yer bırakacak bir sınıf seçmeniz gerekir:

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

StringBuilderolacak iki katına tarafından otomatik olarak büyümek 's sınırına ulaşıldı olduğunda. Böylece, büyüme ağrısını başlangıçta bir kez, bir kez 5.000 baytta, yine 10.000'de, yine 20.000'de göreceksiniz. Dizeleri eklemek her döngü yinelemesinde acıya neden olur.


4
Ayrıca StringBuilder'ın başlangıç ​​boyutunu ayarlamanıza izin verdiğini belirtmek gerekir. 10.000.000 giriş önceden kullanacağınızı biliyorsanız, bazı sıkıntıları görmezden gelmenizi sağlar.
Kyle Baran

3
+1 Soruyu görmek ve iyi tasarıma cevap vermek için. Karşılaştırmalı olarak, "bu sizin dize,
patlamadan

8

Bir dize maksimum uzunluk benim makinede ise 1073741791 .

Gördüğünüz gibi, Dizeler yaygın olarak inandığı gibi tamsayı ile sınırlı değildir.

Bellek kısıtlamaları bir yana, Dizeler 2 30'dan fazla olamaz ( 1.073.741.824 Microsoft CLR (Ortak Dil Çalışma Zamanı) tarafından 2 GB sınırlaması getirildiğinden ) karakterden . Bilgisayarımın izin verdiğinden 33 daha fazla.

Şimdi, burada kendinizi deneyebilirsiniz.

Visual Studio'da yeni bir C # konsol uygulaması oluşturun ve ana yöntemi buraya kopyalayın / yapıştırın:

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

}

Sonuçlarım şöyleydi:

String testi, Nicholas John Joseph Taylor tarafından

Teorik olarak, C # int.MaxValue dizesini desteklemelidir, ancak o zamandan önce bellek tükenir.

Bu, bir dizenin desteklenen maksimum uzunluğunu bulmak için sonuçları daraltmak için hızlı bir testtir.

Test başlar ... şimdi:

Uzunluk = 08.05.2019 12:06

türü 'System.OutOfMemoryException' özel durum. 08/05/2019 12:06. Decimation sonra, Increment değeri 100000000.

türü 'System.OutOfMemoryException' özel durum. 08/05/2019 12:06. Decimation sonra, Artış değeri 10000000'dir. S.Length = 1010000000 08/05/2019 12:06 s.Length = 1020000000 08/05/2019 12:06 s.Length = 1030000000 08/05/2019 12 : 06 s. Uzunluk = 1040000000 08/05/2019 12:06 s. Uzunluk = 1050000000 at 08/05/2019 12:06 s. uzunluk = 1060000000 at 08/05/2019 12:06 s. uzunluk: 1070000000 at 08/05/2019 12:06

türü 'System.OutOfMemoryException' özel durum. 08/05/2019 12:06. Decimation sonra, Artış değeri 1000000. s. Uzunluk = 1071000000 08/05/2019 12:06 s.Length = 1072000000 08/05/2019 12:06 s. Uzunluk = 1073000000 08/05/2019 12 : 06

türü 'System.OutOfMemoryException' özel durum. 08/05/2019 12:06. Decimation sonra, Artış değeri 100000'dir. S.Length = 1073100000 08/05/2019 12:06 s.Length = 1073200000 08/05/2019 12:06 s.Length = 1073300000 08/05/2019 12 : 06 s. Uzunluk = 1073400000 08/05/2019 12:06 s. Uzunluk = 1073500000 at 08/05/2019 12:06 s. uzunluk = 1073600000 at 08/05/2019 12:06 s. uzunluk: 1073700000 at 08/05/2019 12:06

türü 'System.OutOfMemoryException' özel durum. 08/05/2019 12:06. Decimation sonra, Artış değeri 10000'dir. S.Length = 1073710000 08/05/2019 12:06 s.Length = 1073720000 08/05/2019 12:06 s.Length = 1073730000 08/05/2019 12 : 06 s Uzunluk = 1073740000 08/05/2019 12:06

türü 'System.OutOfMemoryException' özel durum. 08/05/2019 12:06. Decimation sonra, Artım değeri 1000'dir. S.Length = 1073741000 08/05/2019 12:06

türü 'System.OutOfMemoryException' özel durum. 08/05/2019 12:06. Decimation sonra, Artış değeri 100'dür. S.Length = 1073741100 08/05/2019 12:06 s.Length = 1073741200 08/05/2019 12:06 s. Uzunluk = 1073741300 08/05/2019 12 : 07 s. Uzunluk = 1073741400 08/05/2019 12:07 s.Length = 1073741500 at 08/05/2019 12:07 s.Length = 1073741600 at 08/05/2019 12:07 s.Length = 1073741700 at 08/05/2019 12:07

türü 'System.OutOfMemoryException' özel durum. 08/05/2019 12:07. Decimation sonra, Artış değeri 10'dur. S = Uzunluk = 1073741710 08/05/2019 12:07 s'de. Uzunluk = 1073741720 08/05/2019 12:07 s'de. Uzunluk = 1073741730 08/05/2019 12 : 07 s. Uzunluk = 1073741740 08/05/2019 12:07 s.Length = 1073741750 at 08/05/2019 12:07 s.Length = 1073741760 at 08/05/2019 12:07 s.Length = 1073741770 at 08/05/2019 12:07 s.Length = 1073741780 at 08/05/2019 12:07 s.Length = 1073741790 at 08/05/2019 12:07

türü 'System.OutOfMemoryException' özel durum. 08/05/2019 12:07. Decimation sonra, Artış değeri 1'dir. S.Length = 1073741791 08/05/2019 12:07

türü 'System.OutOfMemoryException' özel durum. 08/05/2019 12:07. Decimation sonra, Increment değeri 0'dır. Test tamamlandı.

Bir dizenin maksimum uzunluğu 1073741791'dir.

Devam etmek için herhangi bir tuşa basın.

Makinemdeki bir dizenin maksimum uzunluğu 1073741791.

İnsanlar sonuçlarını aşağıdaki yorum olarak gönderebilirlerse çok memnun olurum.

İnsanların aynı veya farklı sonuçları alıp almadığını öğrenmek ilginç olacaktır.


"Gördüğünüz gibi, Dizeler yaygın olarak inandığı gibi tamsayı ile sınırlı değildir." -> c # içindeki bir tamsayı 2.147.483.647'ye kadar çıkabilir ve sonucunuz bu değere çok yakın (32 bayt daha az) ikiye bölünür; bu, bir String'in her karakteri iki bayt üzerinde Unicode olarak depolandığı için mantıklıdır. Bu nedenle, sınır tamsayının büyüklüğü tarafından uygulanmasa bile, dikkate değer ölçüde yakındır.
Ben

2

200 meggs ... bu noktada uygulamanız sanal bir duruşa öğütür, yaklaşık bir konser çalışma hafızasına sahiptir ve o / s, yeniden başlatmanız gerektiği gibi davranmaya başlar.

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
Gerçekten büyük bir dize oluşturmaktan alacağınız davranışın bir demet tahsis ederek ve birleştirerek gördüğünüzle aynı olduğundan emin değilim.
Casey

2

Yana String.Length(bir takma ad olan bir tam sayı olduğu Int32), boyutu ile sınırlıdır Int32.MaxValueUnicode karakterleri. ;-)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.