【问题标题】:Understanding .NET memory mangement and profiling了解 .NET 内存管理和分析
【发布时间】:2020-07-31 12:34:50
【问题描述】:

我有一个 C# 应用程序,它消耗的内存量绝对不足,而且还在稳步增加。我尝试使用 Visual Studio 2019 内存分析器来查找问题。我期待看到某种特定类型的千兆字节对象并找到泄漏,但我发现了一个完全正常的对象集,每种类型不超过 800 KB。

快照大小也表示正常堆大小为 8MB,而进程内存接近 5GB!

我的想法是 GC 出于某种原因拒绝收集未引用的对象,但 GC 标记确实经常出现在内存图表上。我还尝试通过显式调用 GC.Collect() 来清理第 2 代对象。

看起来我不了解内存处理的一些基本概念。 我错过了什么?我该怎么做才能找到问题?

UPD:我还发现了一个奇怪的问题。我在我的软件中使用 FluentFtp 客户端,当我在堆中找到这些条目时(我不使用任何其他网络功能)

我以为我找到了漏洞。这些数字永远不会减少,即使处理线程也无济于事! 但是当我将 ftp 代码提取到单独的应用程序时,问题就消失了。

FtpClient client = new FtpClient(<ip>);
client.Credentials = ...
for (int i = 0; i < 1000; i++)
{
   client.Connect();
   client.Disconnect();
}

最后我只有 63 个这样的对象!请注意,私有内存仅比堆大 86 倍,而不是在我的应用程序中为 625。 完全相同的代码怎么可能在我的应用程序中产生不同的结果?

【问题讨论】:

  • 在我看来,您正在泄漏内存,因为该类没有正确清理自己。您是否尝试过为每个连接运行一个新实例而不是重复使用同一个实例?至于 GC,我已经读过确保 GC 完成其工作的一个好方法是调用 Dispose(),然后在完成后将对象设置为 null。
  • 是的,我的第一个想法是它是 FluentFtp 中的一个错误,但它无法在我的软件之外复制。是的,我尝试使用using 语句为每个连接运行一个新实例,所以我确信它已正确处理。我什至尝试处理整个线程。
  • 尝试将您的 ftp 客户端放入 using 语句以妥善管理它的处置
  • 我不需要丢弃它,但是,正如我所提到的,我已经尝试过了。
  • 看看你的内存截图中的对象和句柄,肯定有一些东西正在创建并且没有正确处理。我相信原因是似乎有一些等待或线程启动并且永远不会完成。查看等待句柄和回调的绝对数量。就好像你每次都在一个新线程上启动某个东西的实例,然后在线程中调用一个异步函数,然后等待那个异步完成,它永远不会这样做,所以线程永远不会死。您是否查看过 taskmgr 中进程的线程数?

标签: c# .net memory-management profiling


【解决方案1】:

看起来确实是 FluentFtp 问题。我将其更改为另一个库,一切都恢复了正常。 但我仍然知道为什么我无法在单独的应用程序中重现此问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-05
    • 2012-03-16
    • 2011-11-11
    相关资源
    最近更新 更多