Title here
Summary here
May 5, 20251 minute
最近遇到了一个典型的内存泄露问题。决定记录一下这次排查的完整思路和经验。
公司存在一个提供API服务的服务器,频繁出现异常崩溃的情况。具体表现为:
初步怀疑是内存相关问题。
首先通过服务器监控工具观察内存使用情况,发现了一个关键线索:
这个现象让我基本确定是内存泄露问题,而且很可能与那个特定的接口有关。
仔细分析了应用日志,发现:
看起来问题就出在这个接口的实现上。
由于是比较老旧的服务,已经很久没有人维护了,拉取了生产环境对应版本的源码,准备在本地重现问题。
调试 -> 窗口 -> 显示诊断工具在调试过程中,诊断工具会实时显示内存使用情况。
通过Visual Studio的内存分析工具,很快就定位到了问题所在。
经过仔细分析代码,发现问题出现在以下代码逻辑中:
// 有问题的代码示例
public class DataService
{
private static Dictionary<int, List<DataModel>> _cache = new Dictionary<int, List<DataModel>>();
public List<DataModel> GetDataByCategory(int categoryId)
{
if (!_cache.ContainsKey(categoryId))
{
var dataList = new List<DataModel>();
// 错误:在循环中重复查询数据库
var subCategories = GetSubCategories(categoryId);
foreach (var subCategory in subCategories)
{
var items = DatabaseQuery($"SELECT * FROM Items WHERE CategoryId = {subCategory.Id}");
dataList.AddRange(items);
}
// 将查询结果存入静态字典缓存
_cache[categoryId] = dataList;
}
return _cache[categoryId];
}
}public List<DataModel> GetDataByCategory(int categoryId)
{
// 优化:使用单次查询替代循环查询
var sql = @"
SELECT i.*
FROM Items i
INNER JOIN SubCategories sc ON i.CategoryId = sc.Id
WHERE sc.ParentCategoryId = @categoryId";
return DatabaseQuery(sql, new { categoryId });
}public class DataService
{
private readonly IMemoryCache _cache;
private readonly TimeSpan _cacheExpiration = TimeSpan.FromMinutes(30);
public DataService(IMemoryCache cache)
{
_cache = cache;
}
public List<DataModel> GetDataByCategory(int categoryId)
{
var cacheKey = $"category_{categoryId}";
if (!_cache.TryGetValue(cacheKey, out List<DataModel> cachedData))
{
cachedData = QueryDataFromDatabase(categoryId);
_cache.Set(cacheKey, cachedData, _cacheExpiration);
}
return cachedData;
}
}