//------------------------------------------------------------------------------ // 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 // 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 // CSDN博客:https://blog.csdn.net/qq_40374647 // 哔哩哔哩视频:https://space.bilibili.com/94253567 // Gitee源代码仓库:https://gitee.com/RRQM_Home // Github源代码仓库:https://github.com/RRQM // API首页:https://www.yuque.com/rrqm/touchsocket/index // 交流QQ群:234762506 // 感谢您的下载和使用 //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Threading; namespace TouchSocket.Core { /// /// 内存池 /// //[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)] public partial class BytePool { private readonly ConcurrentDictionary bytesDictionary = new ConcurrentDictionary(); private readonly Timer m_timer; private long m_fullSize; private long m_maxSize; static BytePool() { Default = new BytePool(); } /// /// 内存池 /// public BytePool() { m_timer = new Timer((o) => { Clear(); }, null, 1000 * 60 * 60, 1000 * 60 * 60); KeyCapacity = 100; AutoZero = false; m_maxSize = 1024 * 1024 * 512; SetBlockSize(1024, 1024 * 1024 * 20); AddSizeKey(10240); } /// /// 默认的内存池实例 /// public static BytePool Default { get; } /// /// 回收内存时,自动归零 /// public bool AutoZero { get; set; } /// /// 键容量 /// public int KeyCapacity { get; set; } /// /// 单个块最大值 /// public int MaxBlockSize { get; private set; } /// /// 允许的内存池最大值 /// public long MaxSize { get => m_maxSize; set { if (value < 1024) { value = 1024; } m_maxSize = value; } } /// /// 单个块最小值 /// public int MinBlockSize { get; private set; } /// /// 添加尺寸键 /// /// /// public bool AddSizeKey(int byteSize) { if (bytesDictionary.TryAdd(byteSize, new BytesQueue(byteSize))) { return true; } return false; } /// /// 清理 /// public void Clear() { bytesDictionary.Clear(); GC.Collect(); } /// /// 确定是否包含指定尺寸键 /// /// /// public bool ContainsSizeKey(int byteSize) { return bytesDictionary.ContainsKey(byteSize); } /// /// 获取所以内存键 /// /// public long[] GetAllSizeKeys() { return bytesDictionary.Keys.ToArray(); } /// /// 获取ByteBlock /// /// 长度 /// 要求长度相同 /// public ByteBlock GetByteBlock(int byteSize, bool equalSize) { return new ByteBlock(byteSize, equalSize); } /// /// 获取ByteBlock /// /// /// public ByteBlock GetByteBlock(int byteSize) { return new ByteBlock(byteSize, false); } /// /// 获取内存核心。获取的核心可以不用归还。 /// 如果要调用归还,切记不要有持久性引用。 /// /// /// /// public byte[] GetByteCore(int byteSize, bool equalSize = false) { BytesQueue bytesCollection; if (equalSize) { //等长 if (bytesDictionary.TryGetValue(byteSize, out bytesCollection)) { if (bytesCollection.TryGet(out byte[] bytes)) { m_fullSize -= byteSize; return bytes; } } else { CheckKeyCapacity(byteSize); } return new byte[byteSize]; } else { //byteSize = HitSize(byteSize); //byteSize = byteSize; //搜索已创建集合 if (bytesDictionary.TryGetValue(byteSize, out bytesCollection)) { if (bytesCollection.TryGet(out byte[] bytes)) { m_fullSize -= byteSize; return bytes; } } else { CheckKeyCapacity(byteSize); } return new byte[byteSize]; } } /// /// 获取内存池容量 /// /// public long GetPoolSize() { long size = 0; foreach (var item in bytesDictionary.Values) { size += item.FullSize; } return size; } /// /// 获取ValueByteBlock /// /// /// /// //[IntelligentCoder.AsyncMethodIgnore] public ValueByteBlock GetValueByteBlock(int byteSize, bool equalSize) { return new ValueByteBlock(byteSize, equalSize); } /// /// 获取ValueByteBlock /// /// /// //[IntelligentCoder.AsyncMethodIgnore] public ValueByteBlock GetValueByteBlock(int byteSize) { return new ValueByteBlock(byteSize, false); } /// /// 回收内存核心。 /// 注意:回收的内存,必须百分百确定该对象没有再被其他引用。不然这属于危险操作。 /// /// public void Recycle(byte[] bytes) { if (bytes == null || bytes.Length > MaxBlockSize || bytes.Length < MinBlockSize) { return; } if (m_maxSize > m_fullSize) { if (bytesDictionary.TryGetValue(bytes.Length, out BytesQueue bytesQueue)) { if (AutoZero) { Array.Clear(bytes, 0, bytes.Length); } m_fullSize += bytes.Length; bytesQueue.Add(bytes); } } else { long size = 0; foreach (var collection in bytesDictionary.Values) { size += collection.FullSize; } m_fullSize = size; } } /// /// 移除尺寸键 /// /// /// public bool RemoveSizeKey(int byteSize) { if (bytesDictionary.TryRemove(byteSize, out BytesQueue queue)) { queue.Clear(); return true; } return false; } /// /// 设置内存块参数 /// /// /// public void SetBlockSize(int minBlockSize, int maxBlockSize) { this.MaxBlockSize = maxBlockSize; this.MinBlockSize = minBlockSize; bytesDictionary.Clear(); } private void CheckKeyCapacity(int byteSize) { if (byteSize < MinBlockSize || byteSize > MaxBlockSize) { return; } if (bytesDictionary.Count < KeyCapacity) { bytesDictionary.TryAdd(byteSize, new BytesQueue(byteSize)); } else { List bytesQueues = bytesDictionary.Values.ToList(); bytesQueues.Sort((x, y) => { return x.m_referenced > y.m_referenced ? -1 : 1; }); for (int i = (int)(bytesQueues.Count * 0.2); i < bytesQueues.Count; i++) { if (bytesDictionary.TryRemove(bytesQueues[i].m_size, out BytesQueue queue)) { queue.Clear(); } } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private int HitSize(int num) { if (num < MinBlockSize) { num = MinBlockSize; } if (num <= 10240)//10k { return 10240; } else if (num <= 65536)//64k { return 65536; } else if (num <= 102400)//100k { return 102400; } else if (num <= 524288) //512k { return 524288; } else if (num <= 1048576)//1Mb { return 1048576; } else if (num <= 1048576 * 2)//2Mb { return 1048576 * 2; } else if (num <= 1048576 * 3)//3Mb { return 1048576 * 3; } else if (num <= 1048576 * 4)//4Mb { return 1048576 * 4; } else if (num <= 1048576 * 5)//5Mb { return 1048576 * 5; } else if (num <= 1048576 * 6)//6Mb { return 1048576 * 6; } else if (num <= 1048576 * 7)//7Mb { return 1048576 * 7; } else if (num <= 1048576 * 8)//8Mb { return 1048576 * 8; } else if (num <= 1048576 * 9)//9Mb { return 1048576 * 9; } else if (num <= 10485760)//10Mb { return 10485760; } else if (num <= 1024 * 1024 * 12)//12Mb { return 1024 * 1024 * 12; } else if (num <= 1024 * 1024 * 15)//15Mb { return 1024 * 1024 * 15; } else if (num <= 1024 * 1024 * 18)//18Mb { return 1024 * 1024 * 18; } else if (num <= 1024 * 1024 * 20)//20Mb { return 1024 * 1024 * 20; } else if (num <= 1024 * 1024 * 30)//30Mb { return 1024 * 1024 * 30; } else if (num <= 1024 * 1024 * 40)//40Mb { return 1024 * 1024 * 40; } else if (num <= 1024 * 1024 * 50)//50Mb { return 1024 * 1024 * 50; } else if (num <= 1024 * 1024 * 100)//100Mb { return 1024 * 1024 * 100; } else if (num <= 1024 * 1024 * 500)//500Mb { return 1024 * 1024 * 500; } else if (num <= 1024 * 1024 * 1024)//1Gb { return 1024 * 1024 * 1024; } else { return num; } } } }