123 lines
4.4 KiB
C#
123 lines
4.4 KiB
C#
using System.Collections.Concurrent;
|
|
|
|
namespace UVC.Data.Mqtt
|
|
{
|
|
public class MqttDataPacketPool
|
|
{
|
|
/// <summary>
|
|
/// MqttDataPacket 인스턴스를 저장하는 스레드 안전 큐입니다.
|
|
/// </summary>
|
|
private static ConcurrentQueue<MqttDataPacket> pool = new ConcurrentQueue<MqttDataPacket>();
|
|
|
|
/// <summary>
|
|
/// 풀의 최대 크기입니다. 이 크기를 초과하는 객체는 풀에 저장되지 않습니다.
|
|
/// </summary>
|
|
private static int maxPoolSize = 1000;
|
|
|
|
// --- 통계용 필드 ---
|
|
private static int _inUseCount = 0; // 현재 사용 중인 MqttDataPacket 인스턴스의 수
|
|
private static int _peakUsage = 0; // 최대 사용량 기록
|
|
private static int _poolMisses = 0; // 풀에서 객체를 찾지 못하고 새로 생성한 횟수
|
|
private static readonly object _statsLock = new object();
|
|
|
|
static MqttDataPacketPool()
|
|
{
|
|
// maxPoolSize만큼의 MqttDataPacket 인스턴스를 미리 생성하여 풀에 추가합니다.
|
|
for (int i = 0; i < maxPoolSize; i++)
|
|
{
|
|
pool.Enqueue(new MqttDataPacket() { IsInPool = true });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 풀에서 MqttDataPacket 인스턴스를 가져옵니다.
|
|
/// 풀이 비어있으면 새 인스턴스를 생성하여 반환합니다.
|
|
/// </summary>
|
|
/// <returns>재사용 가능한 MqttDataPacket 인스턴스</returns>
|
|
public static MqttDataPacket Get()
|
|
{
|
|
bool fromPool = pool.TryDequeue(out var obj);
|
|
|
|
lock (_statsLock)
|
|
{
|
|
_inUseCount++;
|
|
if (_inUseCount > _peakUsage)
|
|
{
|
|
_peakUsage = _inUseCount;
|
|
}
|
|
|
|
// 풀이 비어있어서 새 객체를 만들어야 하는 경우
|
|
if (!fromPool)
|
|
{
|
|
_poolMisses++;
|
|
// 현재 사용량이 최대 풀 크기에 도달했는지 확인
|
|
if (_inUseCount > maxPoolSize)
|
|
{
|
|
int oldSize = maxPoolSize;
|
|
maxPoolSize += 1000;
|
|
//Debug.Log($"MqttDataPacketPool size automatically increased from {oldSize} to {maxPoolSize}. Peak usage: {_peakUsage}");
|
|
}
|
|
}
|
|
}
|
|
|
|
//if (_peakUsage % 100 == 0) Debug.Log($"MqttDataPacketPool stats: {GetStats()}");
|
|
|
|
if (fromPool)
|
|
{
|
|
obj.IsInPool = false;
|
|
}
|
|
return fromPool ? obj : new MqttDataPacket();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 사용이 완료된 MqttDataPacket를 풀에 반환합니다.
|
|
/// 객체는 반환 전에 초기화되어 모든 속성이 제거됩니다.
|
|
/// </summary>
|
|
/// <param name="obj">풀에 반환할 MqttDataPacket 인스턴스</param>
|
|
public static void Return(MqttDataPacket obj)
|
|
{
|
|
if (obj == null || obj.IsInPool) return;
|
|
|
|
bool shouldReturnToPool;
|
|
|
|
lock (_statsLock)
|
|
{
|
|
_inUseCount--;
|
|
shouldReturnToPool = pool.Count < maxPoolSize;
|
|
}
|
|
|
|
if (shouldReturnToPool)
|
|
{
|
|
obj.Reset(); // 재사용 전 완벽한 초기화
|
|
obj.IsInPool = true;
|
|
pool.Enqueue(obj);
|
|
}
|
|
// 풀이 가득 차면 객체는 풀에 추가되지 않고 GC 대상이 됩니다.
|
|
}
|
|
|
|
/// <summary>
|
|
/// 풀의 현재 성능 통계를 문자열로 반환합니다.
|
|
/// </summary>
|
|
/// <returns>풀 통계 (최대 사용량, 현재 사용량, 풀 비어있을 때 생성 횟수, 현재 풀 크기)</returns>
|
|
public static string GetStats()
|
|
{
|
|
lock (_statsLock)
|
|
{
|
|
return $"최대 사용량: {_peakUsage}, 현재 사용량: {_inUseCount}, 풀 비어있을 때 생성 횟수: {_poolMisses}, 현재 풀 크기: {pool.Count}, Max Size: {maxPoolSize}";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 풀 통계를 초기화합니다.
|
|
/// </summary>
|
|
public static void ResetStats()
|
|
{
|
|
lock (_statsLock)
|
|
{
|
|
_peakUsage = 0;
|
|
_poolMisses = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|