2011-09-25 13 views
5

Kiedy mam pusty StringBuilder o pojemności 5 i piszę "cześć, świecie!" do tego, czy standard C# określa nową pojemność StringBuilder? Mam niewyraźne wspomnienie, że jest to dwukrotność długości nowego napisu (aby uniknąć zmiany pojemności przy każdym nowym dołączonym ciągu).Jak zmienia się pojemność StringBuilder?

+4

ten nie jest określony w dowolnym standardzie, jej tylko szczegółów wdrażania – BrokenGlass

+0

StringBuilder nie jest częścią języka C#. Jest częścią bibliotek .net. –

+0

możliwy duplikat [W jaki sposób StringBuilder decyduje, jak duża powinna być jego pojemność?] (Http://stackoverflow.com/questions/4495855/how-does-the-stringbuilder-decide-how-large-its-capacity-should -be) – bzlm

Odpowiedz

15

Zależy od wersji .NET, o której mówisz. Przed .NET 4 StringBuilder użył standard .NET strategy, podwajając pojemność bufora wewnętrznego za każdym razem, gdy trzeba go powiększyć.

StringBuilder został przepisany całkowicie na .NET 4, teraz używający ropes. Rozszerzenie alokacji odbywa się teraz poprzez dodanie kolejnego kawałka liny o długości do 8000 znaków. Nie tak skuteczny jak wcześniejsza strategia, ale unika kłopotów z dużymi buforami blokującymi stertę dużych obiektów. Kod źródłowy jest dostępny ze źródła referencyjnego, jeśli chcesz przyjrzeć mu się bliżej.

+0

Zawiodło to dla nas, gdy uaktualniliśmy nasz produkt z .Net 3.5 do .Net 4.5. Użyliśmy obiektu budującego ciągi jako parametru do natywnego wywołania API poprzez interop. Doprowadziło to do problemu przekroczenia bufora, powodującego awarię procesu. Pamięć sterty ulegała uszkodzeniu, gdy natywny API zwracał długie łańcuchy. Zaczęliśmy zapewniać jawną pojemność w konstruktorze, aby bufor mógł obsłużyć długie ciągi. Z całą pewnością powinno to być wcześniej przerywane również dla długich łańcuchów, ale nigdy nie zostało zgłoszone. Interopowa warstwa działa jakaś sztuczka w .Net 3.5, gdy używamy budowniczych ciągów jako bufora dla natywnych API? – RBT

+0

To powoduje uszkodzenie sterty GC w obu wersjach środowiska wykonawczego. Takie korupcje niekoniecznie muszą zostać wykryte, musisz mieć szczęście. Jasne, masz większe szczęście w .NET 4 –

5

Standard C# nie określa zachowania biblioteki biblioteki BCL, ponieważ nie ma ona nic wspólnego ze specyfikacją języka.

O ile mi wiadomo, rzeczywiste zachowanie nie jest zdefiniowane w żadnej specyfikacji i jest zależne od implementacji.

AFAIK, Wdrożenie MS podwoi wydajność po osiągnięciu obecnej przepustowości.

Zobacz wcześniejsze pytania WSTĘPNE this i this.


Aktualizacja:

ten został zmieniony w .NET 4.0. jak opisano przez Hans w his answer. Teraz używa się ropes, dodając kolejne 8000 znaków naraz.

MSDN jednak jest bardzo ostrożny, aby podkreślić, że rzeczywiste zachowanie jest realizacja specyficznych:

StringBuilder dynamicznie przydziela więcej przestrzeni gdy wymagane i zwiększa pojemność odpowiednio. Ze względu na wydajność, StringBuilder może przydzielić więcej pamięci niż potrzeba. Ilość przydzielonej pamięci jest zależna od implementacji.

+2

Nie używamy już strategii podwójnego wyczerpania. –

+1

@Eric - Dzięki za poprawienie mnie. To i odpowiedź Hansa dała mi więcej szczegółów. – Oded

-1

New StringBuilder (.NET 4.5 lub nowszy) przydziela bufor wewnętrzny m_ChunkChars wymaganych przez parametr Pojemność:

public StringBuilder(int capacity) { ... m_ChunkChars = new char[capacity]; ... }

Tak więc, jeśli pojemność jest mniejsza niż 40K znaków idzie na mały przedmiot sterty. Jednak (w przeciwieństwie do popularnego przekonania), StringBuilder nadal będzie przeznaczyć na dużej sterty Object czy później, nazywamy sb.Append(...some string larger than 40K chars...); Ewentualna poprawka można znaleźć tutaj: https://github.com/amikunov/Large-Object-Heap-Fix-For-.NET-String-Builder

+1

Nie ma to nic wspólnego z pytaniem. – Servy