1 // ==++== 2 // 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // 5 // ==--== 6 /*============================================================ 7 ** 8 ** Class: StringBuilderCache 9 ** 10 ** Purpose: provide a cached reusable instance of stringbuilder 11 ** per thread it's an optimisation that reduces the 12 ** number of instances constructed and collected. 13 ** 14 ** Acquire - is used to get a string builder to use of a 15 ** particular size. It can be called any number of 16 ** times, if a stringbuilder is in the cache then 17 ** it will be returned and the cache emptied. 18 ** subsequent calls will return a new stringbuilder. 19 ** 20 ** A StringBuilder instance is cached in 21 ** Thread Local Storage and so there is one per thread 22 ** 23 ** Release - Place the specified builder in the cache if it is 24 ** not too big. 25 ** The stringbuilder should not be used after it has 26 ** been released. 27 ** Unbalanced Releases are perfectly acceptable. It 28 ** will merely cause the runtime to create a new 29 ** stringbuilder next time Acquire is called. 30 ** 31 ** GetStringAndRelease 32 ** - ToString() the stringbuilder, Release it to the 33 ** cache and return the resulting string 34 ** 35 ===========================================================*/ 36 using System.Threading; 37 38 namespace System.Text 39 { 40 internal static class StringBuilderCache 41 { 42 // The value 360 was chosen in discussion with performance experts as a compromise between using 43 // as litle memory (per thread) as possible and still covering a large part of short-lived 44 // StringBuilder creations on the startup path of VS designers. 45 private const int MAX_BUILDER_SIZE = 360; 46 47 [ThreadStatic] 48 private static StringBuilder CachedInstance; 49 Acquire(int capacity = StringBuilder.DefaultCapacity)50 public static StringBuilder Acquire(int capacity = StringBuilder.DefaultCapacity) 51 { 52 if(capacity <= MAX_BUILDER_SIZE) 53 { 54 StringBuilder sb = StringBuilderCache.CachedInstance; 55 if (sb != null) 56 { 57 // Avoid stringbuilder block fragmentation by getting a new StringBuilder 58 // when the requested size is larger than the current capacity 59 if(capacity <= sb.Capacity) 60 { 61 StringBuilderCache.CachedInstance = null; 62 sb.Clear(); 63 return sb; 64 } 65 } 66 } 67 return new StringBuilder(capacity); 68 } 69 Release(StringBuilder sb)70 public static void Release(StringBuilder sb) 71 { 72 if (sb.Capacity <= MAX_BUILDER_SIZE) 73 { 74 StringBuilderCache.CachedInstance = sb; 75 } 76 } 77 GetStringAndRelease(StringBuilder sb)78 public static string GetStringAndRelease(StringBuilder sb) 79 { 80 string result = sb.ToString(); 81 Release(sb); 82 return result; 83 } 84 } 85 } 86