|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Diagnostics;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
using System.Threading;
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
namespace SocketExample
|
|
|
{
|
|
|
public static class MemoryManager
|
|
|
{
|
|
|
private static readonly object _lock = new object();
|
|
|
private static DateTime _lastCleanupTime = DateTime.MinValue;
|
|
|
private static Timer _cleanupTimer;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 初始化内存管理器
|
|
|
/// </summary>
|
|
|
/// <param name="cleanupIntervalMinutes">清理间隔(分钟)</param>
|
|
|
public static void Initialize(int cleanupIntervalMinutes = 5)
|
|
|
{
|
|
|
// 创建定时清理任务
|
|
|
_cleanupTimer = new Timer(CleanupCallback, null,
|
|
|
TimeSpan.FromMinutes(cleanupIntervalMinutes),
|
|
|
TimeSpan.FromMinutes(cleanupIntervalMinutes));
|
|
|
|
|
|
Console.WriteLine($"MemoryManager已启动,每{cleanupIntervalMinutes}分钟检查一次内存");
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 立即清理内存
|
|
|
/// </summary>
|
|
|
/// <param name="aggressive">是否激进清理(包括第2代)</param>
|
|
|
public static void ForceCleanup(bool aggressive = false)
|
|
|
{
|
|
|
lock (_lock)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
long before = GC.GetTotalMemory(true);
|
|
|
Console.WriteLine($"清理前内存: {FormatBytes(before)}");
|
|
|
|
|
|
if (aggressive)
|
|
|
{
|
|
|
// 激进模式:清理所有代
|
|
|
GC.Collect(2, GCCollectionMode.Forced);
|
|
|
GC.WaitForPendingFinalizers();
|
|
|
GC.Collect();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// 温和模式:只清理第0代和第1代
|
|
|
GC.Collect(0, GCCollectionMode.Optimized);
|
|
|
GC.Collect(1, GCCollectionMode.Optimized);
|
|
|
}
|
|
|
|
|
|
long after = GC.GetTotalMemory(true);
|
|
|
Console.WriteLine($"清理后内存: {FormatBytes(after)}");
|
|
|
Console.WriteLine($"释放了: {FormatBytes(before - after)}");
|
|
|
|
|
|
_lastCleanupTime = DateTime.Now;
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Console.WriteLine($"内存清理失败: {ex.Message}");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 智能清理 - 根据内存使用情况决定清理策略
|
|
|
/// </summary>
|
|
|
public static void SmartCleanup()
|
|
|
{
|
|
|
var memoryInfo = GetMemoryInfo();
|
|
|
|
|
|
Console.WriteLine($"当前内存使用: {memoryInfo.UsagePercentage:F1}% ({memoryInfo.ProcessMemoryMB:F1}MB)");
|
|
|
|
|
|
if (memoryInfo.UsagePercentage > 85)
|
|
|
{
|
|
|
Console.WriteLine("内存使用超过85%,执行深度清理...");
|
|
|
ForceCleanup(true); // 激进清理
|
|
|
}
|
|
|
else if (memoryInfo.UsagePercentage > 70)
|
|
|
{
|
|
|
Console.WriteLine("内存使用超过70%,执行普通清理...");
|
|
|
ForceCleanup(false); // 普通清理
|
|
|
}
|
|
|
else if (memoryInfo.UsagePercentage > 50 &&
|
|
|
DateTime.Now - _lastCleanupTime > TimeSpan.FromMinutes(10))
|
|
|
{
|
|
|
Console.WriteLine("内存使用较高且超过10分钟未清理,执行轻度清理...");
|
|
|
ForceCleanup(false);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Console.WriteLine("内存使用正常,跳过清理");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取内存信息
|
|
|
/// </summary>
|
|
|
public static MemoryInfo GetMemoryInfo()
|
|
|
{
|
|
|
var process = Process.GetCurrentProcess();
|
|
|
process.Refresh();
|
|
|
|
|
|
long processMemory = process.WorkingSet64;
|
|
|
//long totalPhysicalMemory = GetTotalPhysicalMemory();
|
|
|
|
|
|
return new MemoryInfo
|
|
|
{
|
|
|
ProcessMemoryBytes = processMemory,
|
|
|
ProcessMemoryMB = processMemory / 1024.0 / 1024.0,
|
|
|
Gen0Collections = GC.CollectionCount(0),
|
|
|
Gen1Collections = GC.CollectionCount(1),
|
|
|
Gen2Collections = GC.CollectionCount(2)
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 监控内存使用,超过阈值自动清理
|
|
|
/// </summary>
|
|
|
public static void StartMonitoring(int thresholdMB = 100, int checkIntervalSeconds = 30)
|
|
|
{
|
|
|
Task.Run(async () =>
|
|
|
{
|
|
|
while (true)
|
|
|
{
|
|
|
await Task.Delay(TimeSpan.FromSeconds(checkIntervalSeconds));
|
|
|
|
|
|
var info = GetMemoryInfo();
|
|
|
|
|
|
if (info.ProcessMemoryMB > thresholdMB)
|
|
|
{
|
|
|
Console.WriteLine($"内存使用超过{thresholdMB}MB,当前{info.ProcessMemoryMB:F1}MB,触发自动清理...");
|
|
|
SmartCleanup();
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
private static void CleanupCallback(object state)
|
|
|
{
|
|
|
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 定时内存检查...");
|
|
|
SmartCleanup();
|
|
|
}
|
|
|
|
|
|
private static string FormatBytes(long bytes)
|
|
|
{
|
|
|
string[] suffixes = { "B", "KB", "MB", "GB" };
|
|
|
int suffixIndex = 0;
|
|
|
double number = bytes;
|
|
|
|
|
|
while (number >= 1024 && suffixIndex < suffixes.Length - 1)
|
|
|
{
|
|
|
number /= 1024;
|
|
|
suffixIndex++;
|
|
|
}
|
|
|
|
|
|
return $"{number:F2} {suffixes[suffixIndex]}";
|
|
|
}
|
|
|
|
|
|
public class MemoryInfo
|
|
|
{
|
|
|
public long ProcessMemoryBytes { get; set; }
|
|
|
public double ProcessMemoryMB { get; set; }
|
|
|
public long TotalPhysicalMemoryBytes { get; set; }
|
|
|
public double TotalPhysicalMemoryMB { get; set; }
|
|
|
public double UsagePercentage { get; set; }
|
|
|
public int Gen0Collections { get; set; }
|
|
|
public int Gen1Collections { get; set; }
|
|
|
public int Gen2Collections { get; set; }
|
|
|
}
|
|
|
}
|
|
|
}
|