StringBuilderCache.cs 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. #nullable enable
  5. namespace System.Text
  6. {
  7. /// <summary>Provide a cached reusable instance of stringbuilder per thread.</summary>
  8. internal static class StringBuilderCache
  9. {
  10. // The value 360 was chosen in discussion with performance experts as a compromise between using
  11. // as litle memory per thread as possible and still covering a large part of short-lived
  12. // StringBuilder creations on the startup path of VS designers.
  13. private const int MaxBuilderSize = 360;
  14. private const int DefaultCapacity = 16; // == StringBuilder.DefaultCapacity
  15. // WARNING: We allow diagnostic tools to directly inspect this member (t_cachedInstance).
  16. // See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details.
  17. // Please do not change the type, the name, or the semantic usage of this member without understanding the implication for tools.
  18. // Get in touch with the diagnostics team if you have questions.
  19. [ThreadStatic]
  20. private static StringBuilder? t_cachedInstance;
  21. /// <summary>Get a StringBuilder for the specified capacity.</summary>
  22. /// <remarks>If a StringBuilder of an appropriate size is cached, it will be returned and the cache emptied.</remarks>
  23. public static StringBuilder Acquire(int capacity = DefaultCapacity)
  24. {
  25. if (capacity <= MaxBuilderSize)
  26. {
  27. StringBuilder? sb = t_cachedInstance;
  28. if (sb != null)
  29. {
  30. // Avoid stringbuilder block fragmentation by getting a new StringBuilder
  31. // when the requested size is larger than the current capacity
  32. if (capacity <= sb.Capacity)
  33. {
  34. t_cachedInstance = null;
  35. sb.Clear();
  36. return sb;
  37. }
  38. }
  39. }
  40. return new StringBuilder(capacity);
  41. }
  42. /// <summary>Place the specified builder in the cache if it is not too big.</summary>
  43. public static void Release(StringBuilder sb)
  44. {
  45. if (sb.Capacity <= MaxBuilderSize)
  46. {
  47. t_cachedInstance = sb;
  48. }
  49. }
  50. /// <summary>ToString() the stringbuilder, Release it to the cache, and return the resulting string.</summary>
  51. public static string GetStringAndRelease(StringBuilder sb)
  52. {
  53. string result = sb.ToString();
  54. Release(sb);
  55. return result;
  56. }
  57. }
  58. }