| | |
| | | using System.Collections; |
| | | using System.Text; |
| | | using System; |
| | | using System.Collections.Concurrent; |
| | | |
| | | |
| | | // AI提醒实际在现代编辑器中,低于4个字符串的+ 操作符的性能和 string.Concat 几乎相同,会被智能优化为 string.Concat |
| | | public class StringUtility |
| | | { |
| | | public static readonly string[] splitSeparator = new string[] { "|" }; |
| | | |
| | | // 对象池方案:线程安全的StringBuilder池 |
| | | private static readonly ConcurrentQueue<StringBuilder> _stringBuilderPool = new ConcurrentQueue<StringBuilder>(); |
| | | private const int MAX_POOL_SIZE = 32; // 增加池大小以适应高并发 |
| | | private const int DEFAULT_CAPACITY = 64; |
| | | private const int SMALL_CAPACITY = 64; // 适用于小规模拼接 |
| | | private const int TINY_CAPACITY = 32; // 适用于极小规模拼接 |
| | | private const int MEDIUM_CAPACITY = 128; // 新增中等容量级别 |
| | | private const int LARGE_CAPACITY = 256; // 新增大容量级别 |
| | | |
| | | // 新增:为循环调用的优化版本(复用StringBuilder) |
| | | [ThreadStatic] |
| | | private static StringBuilder _threadLocalStringBuilder; |
| | | |
| | | |
| | | /// <summary> |
| | | /// 获取当前线程的StringBuilder |
| | | /// 智能容量估算(优化版) |
| | | /// </summary> |
| | | private static StringBuilder GetThreadLocalStringBuilder() |
| | | private static int EstimateCapacity(params string[] objects) |
| | | { |
| | | if (_threadLocalStringBuilder == null) |
| | | if (objects == null || objects.Length == 0) |
| | | return TINY_CAPACITY; |
| | | |
| | | int totalLength = 0; |
| | | |
| | | // 单次遍历计算总长度,提高性能 |
| | | foreach (string str in objects) |
| | | { |
| | | _threadLocalStringBuilder = new StringBuilder(); |
| | | if (str != null) |
| | | totalLength += str.Length; |
| | | } |
| | | return _threadLocalStringBuilder; |
| | | |
| | | // 更精细的容量策略,减少内存浪费 |
| | | if (totalLength <= TINY_CAPACITY) |
| | | return TINY_CAPACITY; |
| | | else if (totalLength <= SMALL_CAPACITY) |
| | | return SMALL_CAPACITY; |
| | | else if (totalLength <= MEDIUM_CAPACITY) |
| | | return MEDIUM_CAPACITY; |
| | | else if (totalLength <= LARGE_CAPACITY) |
| | | return LARGE_CAPACITY; |
| | | else |
| | | // 对于超大字符串,预留25%的缓冲空间(减少内存浪费) |
| | | return totalLength + (totalLength >> 2); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 智能字符串拼接方法,自动选择最优策略 |
| | | /// - 2-4个字符串:直接使用 string.Concat() (最高性能) |
| | | /// - 5个以上字符串:使用线程本地 StringBuilder 复用 (循环优化) |
| | | /// 从对象池获取StringBuilder |
| | | /// </summary> |
| | | private static StringBuilder GetPooledStringBuilder(int capacity = DEFAULT_CAPACITY) |
| | | { |
| | | if (_stringBuilderPool.TryDequeue(out StringBuilder sb)) |
| | | { |
| | | sb.Clear(); |
| | | // 如果容量不足,重新创建 |
| | | if (sb.Capacity < capacity) |
| | | { |
| | | sb = new StringBuilder(capacity); |
| | | } |
| | | return sb; |
| | | } |
| | | return new StringBuilder(capacity); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 将StringBuilder归还到对象池(优化版) |
| | | /// </summary> |
| | | private static void ReturnToPool(StringBuilder sb) |
| | | { |
| | | if (sb == null) |
| | | return; |
| | | |
| | | // 容量过大或过长,不回收以避免内存问题 |
| | | if (sb.Capacity > 2048 || sb.Length > 1024) |
| | | { |
| | | SecureClear(sb); |
| | | return; |
| | | } |
| | | |
| | | // 池未满时才回收 |
| | | if (_stringBuilderPool.Count < MAX_POOL_SIZE) |
| | | { |
| | | sb.Clear(); |
| | | _stringBuilderPool.Enqueue(sb); |
| | | } |
| | | else |
| | | { |
| | | // 池满时进行安全清理 |
| | | SecureClear(sb); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 安全清理StringBuilder内容(防止敏感数据泄露) |
| | | /// </summary> |
| | | private static void SecureClear(StringBuilder sb) |
| | | { |
| | | if (sb == null || sb.Length == 0) |
| | | return; |
| | | |
| | | // 基础清理 |
| | | sb.Clear(); |
| | | |
| | | // 安全清理:用空字符覆盖缓冲区 |
| | | // #if UNITY_EDITOR || DEVELOPMENT_BUILD |
| | | // // 仅在开发版本中执行更彻底的清理,避免影响性能 |
| | | // int originalCapacity = sb.Capacity; |
| | | // if (originalCapacity <= 1024) // 仅对小容量StringBuilder进行安全清理 |
| | | // { |
| | | // sb.Capacity = originalCapacity; |
| | | // for (int i = 0; i < originalCapacity; i++) |
| | | // { |
| | | // sb.Append('\0'); |
| | | // } |
| | | // sb.Clear(); |
| | | // } |
| | | // #endif |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 智能字符串拼接方法(优化版),自动选择最优策略 |
| | | /// - 1-4个字符串:直接使用 string.Concat() (最高性能) |
| | | /// - 4-8个字符串:使用对象池 StringBuilder,容量预分配 |
| | | /// - 9个以上字符串:使用对象池 StringBuilder + 容量估算 |
| | | /// </summary> |
| | | public static string Concat(params string[] _objects) |
| | | { |
| | | if (_objects == null || _objects.Length == 0) |
| | | return string.Empty; |
| | | |
| | | // 少量字符串直接使用Concat,性能最佳 |
| | | if (_objects.Length <= 4) |
| | | { |
| | | return string.Concat(_objects); |
| | | } |
| | | |
| | | // 大量字符串使用线程本地StringBuilder,避免重复创建 |
| | | var sb = GetThreadLocalStringBuilder(); |
| | | sb.Clear(); |
| | | foreach (string str in _objects) |
| | | // 中等数量字符串使用简单容量策略 |
| | | int estimatedCapacity; |
| | | if (_objects.Length <= 8) |
| | | { |
| | | sb.Append(str); |
| | | estimatedCapacity = DEFAULT_CAPACITY; |
| | | } |
| | | return sb.ToString(); |
| | | } |
| | | |
| | | // AI提醒实际在现代编辑器中,低于4个字符串的+ 操作符的性能和 string.Concat 几乎相同,会被智能优化为 string.Concat |
| | | // 添加常用2个字符串拼接的优化版本 |
| | | public static string Contact(string str1, string str2) |
| | | { |
| | | return string.Concat(str1, str2); |
| | | } |
| | | |
| | | // 添加常用3个字符串拼接的优化版本 |
| | | public static string Contact(string str1, string str2, string str3) |
| | | { |
| | | return string.Concat(str1, str2, str3); |
| | | } |
| | | |
| | | // 添加常用4个字符串拼接的优化版本 |
| | | public static string Contact(string str1, string str2, string str3, string str4) |
| | | { |
| | | return string.Concat(str1, str2, str3, str4); |
| | | } |
| | | |
| | | else |
| | | { |
| | | // 大量字符串才进行容量估算(优化性能) |
| | | estimatedCapacity = EstimateCapacity(_objects); |
| | | } |
| | | |
| | | |
| | | var sb = GetPooledStringBuilder(estimatedCapacity); |
| | | try |
| | | { |
| | | foreach (string str in _objects) |
| | | { |
| | | sb.Append(str); |
| | | } |
| | | return sb.ToString(); |
| | | } |
| | | finally |
| | | { |
| | | ReturnToPool(sb); |
| | | } |
| | | } |
| | | |
| | | |
| | | public static string FormatSpeed(float speed) |
| | | { |
| | | if (speed > 1048576f) |
| | | { |
| | | return Contact((speed / 1048576f).ToString("f1"), " M/S"); |
| | | return Concat((speed / 1048576f).ToString("f1"), " M/S"); |
| | | } |
| | | else if (speed > 1024f) |
| | | { |
| | | return Contact((speed / 1024f).ToString("f1"), " KB/S"); |
| | | return Concat((speed / 1024f).ToString("f1"), " KB/S"); |
| | | } |
| | | else |
| | | { |
| | | return Contact(speed.ToString("f1"), " B/S"); |
| | | return Concat(speed.ToString("f1"), " B/S"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 预热对象池(在应用启动时调用) |
| | | /// </summary> |
| | | public static void WarmupPool(int count = 4) |
| | | { |
| | | // 预热不同容量的StringBuilder以适应不同场景 |
| | | for (int i = 0; i < count && _stringBuilderPool.Count < MAX_POOL_SIZE; i++) |
| | | { |
| | | _stringBuilderPool.Enqueue(new StringBuilder(DEFAULT_CAPACITY)); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | } |