代码之家  ›  专栏  ›  技术社区  ›  Page

当前加载的类不断增加-内存泄漏

  •  6
  • Page  · 技术社区  · 17 年前

    我的服务内存泄漏非常缓慢。如果我分析一下。NET CLR加载计数器,我看到 当前加载的类 计数器不断增加和匹配 已加载的类总数 柜台随时。这给我的印象是,内存泄漏与资源未被释放有关(这只是猜测)。

    该服务每次执行任务时都会创建新的appDomains(插件架构)。

    我需要弄清楚类名,以便缩小泄漏的原因。我不是很精通Winger,但我想知道是否有人能教我列举这些步骤 装载的 班级。

    我确实有源代码,所以如果需要,我可以获得符号文件。提前感谢您的帮助!

    9 回复  |  直到 17 年前
        1
  •  2
  •   Andrew Rollings    17 年前

    这是.net 2.0还是更高版本?如果是这样,您可能不会卸载 AppDomain (正如Jon Skeet在评论中所说)。

    如果它是1.1或更低,则存在错误 应用程序域 卸载功能。即,当发生以下情况时,它不会释放内存或释放资源 应用程序域 已“卸载”。

    (这在.net 2.0版本中已修复)

        2
  •  2
  •   Pop Catalin    17 年前

    您始终可以检查AppDomain中加载了哪些程序集:

    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
    {
          Console.WriteLine(assembly.FullName);
    }
    

    因此,如果您不小心将程序集加载到错误的域中,则很难看到。

    编辑:

    如果你想使用WinDgb SOS, here 是支持的命令。您最有可能感兴趣的是:DumpDomain、DumpClass、DumpAssembly、EEHeap。..

        3
  •  2
  •   Page    17 年前

    我认为这个问题实际上是由一系列嵌套在RemoteTaskRunner MBRO内部的未处理FileSystemWatcher实例引起的。我仍然不确定我是否完全解决了内存泄漏问题,但我肯定能看出其中的区别。

    这似乎不是FileSystemWatchers第一次给我带来问题。 :)

    感谢大家(尤其是麻风病人)帮助我!

        4
  •  1
  •   Will Dean    17 年前

    我建议使用适当的内存分析器,比如“.NET内存分析器”- http://memprofiler.com/ 你当然可以在评估中尝试一下,看看它是否是一种有帮助的工具。

    这将使您比WinDBG/SoS的核心内容更容易看到所有活动对象。

        5
  •  1
  •   leppie    17 年前

    正如另一个答案所说,AppDomain。应使用Unload()。

    但是,您需要注意不要在多个地方加载程序集,尤其是主应用程序域。

    查看AppDomain的MSDN文档。Load(AssemblyName)以了解上述情况是如何发生的。

    同样在同一行中,你确定你使用了正确的远程类吗?否则,上述情况肯定会发生。

        6
  •  1
  •   Page    17 年前

    我刚刚在Suzanne Cook的博客上读到这篇文章。

    http://blogs.msdn.com/suzcook/archive/2003/06/12/57169.aspx

    一定不要通过任何 类型/组件等实例(除 您的MarshalByRefObject类型)返回 原始应用程序域。如果你这样做,它 将导致这些组件 加载到原始appdomain中。如果 appdomain设置不同 在这两个应用程序域之间 组件可能无法装载到那里。 另外,即使他们成功了 加载后,组件将保持不变 在目标之后加载并锁定 appdomain被卸载,即使 原始的appdomain从不使用它们。

    当她说任何类型/组件等时。她可能是什么类型的?我之所以问这个问题,是因为我的MarshalByRefObject(RemoteTaskRunner)在任务运行后确实返回了DateTime对象。这是否会导致插件程序集加载到我的主appDomain中(并最终导致内存泄漏)?

        7
  •  1
  •   Kibbee    17 年前

    每当有人报告内存泄漏时,我总是把这个扔出去,因为它让我忙了几个星期。不要在调试模式下运行应用程序。如果您在中以调试模式运行应用程序。Net 2.0+(在.Net 1.1中没有发生),你实例化一个包含事件的类,即使你没有引发事件,它也只会占用一小部分内存。这会极大地影响长时间运行的应用程序,如服务和web应用程序,因为随着时间的推移,实例化对象后消耗的少量内存会加起来相当多。

        8
  •  0
  •   StingyJack    17 年前

    编辑:在阅读了其他一些帖子后,在使用更好的分析器并解决appDomain问题后,应该考虑这些帖子。

    您可能希望在服务中添加性能计数器,以便至少可以跟踪您创建的对象。这将有助于您确定课程。加载的是你的类或CLR类。

    此外,在显式创建和销毁对象时添加一些调试日志可能会有所帮助。

    作为最后的手段,你可以 尝试 放GC。在那里收集(),看看调用它是否能纠正你的问题。不是 这个 修复,但测试它会让你知道这是一个选项。

        9
  •  0
  •   Page    17 年前

    AppDomain已卸载,但leppie的响应让我怀疑插件程序集是否同时加载到主AppDomain和辅助AppDomain中。当我查看性能计数器时,当前AppDomain计数不会不断增加。

    应用程序应该创建一个Secondary appDomain,然后加载一个单独的插件程序集。也许一些代码会有所帮助:

    从主AppDomain创建辅助AppDomain:

    AppDomainSetup ads = new AppDomainSetup();
    ads.ApplicationName = "RemoteAgentLib";
    ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
    ads.PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory;
    ads.ShadowCopyDirectories = AppDomain.CurrentDomain.BaseDirectory;
    ads.ShadowCopyFiles = "true";
    
    m_domain = AppDomain.CreateDomain("RemoteTaskRunner", null, ads);
    

    使用RemoteTaskRunner在辅助appDomain中加载插件:

    RemoteTaskRunner taskRunner = m_domain.CreateInstanceAndUnwrap(
                        Assembly.GetExecutingAssembly().FullName,
                        typeof (RemoteTaskRunner).FullName) as RemoteTaskRunner;
    taskRunner.LoadTask(taskInfo.Assembly, taskInfo.Type);
    

    使用RemoteTaskRunner在辅助appDomain中执行任务:

    [Serializable]
    internal class RemoteTaskRunner : MarshalByRefObject
    {
        private ITask m_task;
    
        public RemoteTaskRunner()
        {
        }
    
        internal void LoadTask(string assembly, string type)
        {
            // This assembly should load in the secondary appDomain.
            Assembly taskAssembly = AppDomain.CurrentDomain.Load(assembly);
            m_task = taskAssembly.CreateInstance(type) as ITask;
        }
    
        internal void RunTask(string taskConfig)
        {
            // This method should run in the secondary appDomain.
            m_task.RunTask(taskConfig, m_logger);
        }
    ...
    ...
    

    要执行插件任务,在Primary appDomain中使用以下代码行:

    taskRunner.RunTask(taskInfo.TaskConfig);
    

    任务完成后,appDomain将被卸载:

    AppDomain.Unload(m_domain);