我可以在C#中获取某种类型的活动对象的实例吗?

时间:2022-03-28 16:14:27

This is a C# 3.0 question. Can I use reflection or memory management classes provided by .net framework to count the total alive instances of a certain type in the memory?

这是一个C#3.0问题。我可以使用.net框架提供的反射或内存管理类来计算内存中某种类型的总活动实例吗?

I can do the same thing using a memory profiler but that requires extra time to dump the memory and involves a third party software. What I want is only to monitor a certain type and I want a light-weighted method which can go easily to unit tests. The purpose to count the alive instances is to ensure I don't have any expected living instances that cause "memory leak".

我可以使用内存分析器做同样的事情但是需要额外的时间来转储内存并涉及第三方软件。我想要的只是监控某种类型,我想要一种轻量级的方法,可以很容易地进行单元测试。计算活动实例的目的是确保我没有任何导致“内存泄漏”的预期生存实例。

Thanks.

2 个解决方案

#1


To do it entirely within the application you could do an instance-counter, but it would need to be explicitly coded and managed inside each class--there's no silver bullet that I'm aware of to let you query the framework from within the executing code to see how many instances are alive.

要完全在应用程序中完成,你可以做一个实例计数器,但它需要在每个类中进行显式编码和管理 - 我不知道让你从执行中查询框架的银弹用于查看有多少实例存活的代码。

What you're asking for is really the domain of a profiler. You can purchase one or build your own, but it requires your application to run as a child process of the profiler. Rolling your own isn't an easy undertaking, by the way.

您所要求的实际上是分析器的领域。您可以购买一个或构建自己的应用程序,但它需要您的应用程序作为分析器的子进程运行。顺便说一句,滚动自己并不是一件容易的事。

If you want to consider the instance counter it would have to be something like:

如果你想考虑实例计数器,它必须是这样的:

public class MyClass : IDisposable
    public MyClass()
    {
        ++ClassInstances;
    }

    public void Dispose()
    {
        --ClassInstances;
    }

    private static new object _ClassInstancesLock;
    private static int _ClassInstances;
    private static int ClassInstances
    {
        get
        {
            lock (_ClassInstancesLock)
            {
                return _ClassInstances
            }
        }
    }

This is just a really rough sample, no tests for compilation; 0% guarantee for thread-safety (critical for this type of approach) and it leaves the door wide open for Dispose to be called, the instance counter to decrement, but for the object not to properly GC. To diagnose that bundle of joy you'll need, you guessed it, a professional profiler--or at least windbg.

这只是一个非常粗略的样本,没有编译测试; 0%保证线程安全(对于这种类型的方法至关重要)并且它使门敞开以便调用Dispose,实例计数器减少,但是对象不能正确GC。为了诊断你需要的那束快乐,你猜对了,一个专业的探测器 - 或至少是windbg。

Edit: I just noticed the very last line of your question and needed to say that my above approach, as shoddy and failure-prone as it is, is almost guaranteed to deceive and lie to you about the true number of instances if you're experiencing a leak. The best tool, IMO, for attacking these problems is ANTS Memory Profiler. Version 5 is a double-edge in that they broke Performance and Memory profiler into two seperate SKUs (used to be bundled together) but Memory Profiler 5.0 is absolutely lightning fast. Profiling these problems used to be slow as molases, but they've gotten around it somehome.

编辑:我刚刚注意到你问题的最后一行,并且需要说我的上述方法,如同粗制滥造和失败一样,几乎可以保证欺骗并欺骗你,如果你是真实的实例数量遇到泄漏。用于攻击这些问题的最佳工具IMO是ANTS Memory Profiler。版本5是双边缘,因为它们将性能和内存分析器分成两个单独的SKU(过去捆绑在一起),但Memory Profiler 5.0绝对闪电般快。分析这些问题过去常常像潮湿一样缓慢,但他们已经解决了一些问题。

Unless this is for a personal project with 0 intent of redistribution you should invest the few hundred dollars needed for ANTS--but by all means use it's trial period first. It's a great tool for exactly this kind of analysis.

除非这是针对具有重新分配意图的个人项目,否则您应该投入ANTS所需的几百美元 - 但无论如何都要首先使用它的试用期。对于这种分析来说,它是一个很好的工具。

#2


The only way I see to do this is without any form of instrumentation to use the CLR Profiling API to track object lifetimes. I'm not aware of any APIs available to the managed code to do the same thing, and, so far as I know, CLR doesn't keep the list of live objects anywhere (so even with profiler API you have to create the data structures for that yourself).

我看到这样做的唯一方法是没有任何形式的工具来使用CLR Profiling API来跟踪对象的生命周期。我不知道托管代码可以使用任何API来执行相同的操作,而且据我所知,CLR不会将实时对象列表保留在任何位置(因此即使使用分析器API,您也必须创建数据你自己的结构)。

VB.NET has a feature where it lets you track objects in debugger, but it actually emits additional code specifically for that (which basically registers all created objects in internal list of weak references). You could do that as well, using e.g. PostSharp to post-process your assemblies.

VB.NET有一个功能,它允许你跟踪调试器中的对象,但它实际上发出了专门用于它的附加代码(它基本上将所有创建的对象注册在弱引用的内部列表中)。您也可以使用例如PostSharp后处理您的程序集。

#1


To do it entirely within the application you could do an instance-counter, but it would need to be explicitly coded and managed inside each class--there's no silver bullet that I'm aware of to let you query the framework from within the executing code to see how many instances are alive.

要完全在应用程序中完成,你可以做一个实例计数器,但它需要在每个类中进行显式编码和管理 - 我不知道让你从执行中查询框架的银弹用于查看有多少实例存活的代码。

What you're asking for is really the domain of a profiler. You can purchase one or build your own, but it requires your application to run as a child process of the profiler. Rolling your own isn't an easy undertaking, by the way.

您所要求的实际上是分析器的领域。您可以购买一个或构建自己的应用程序,但它需要您的应用程序作为分析器的子进程运行。顺便说一句,滚动自己并不是一件容易的事。

If you want to consider the instance counter it would have to be something like:

如果你想考虑实例计数器,它必须是这样的:

public class MyClass : IDisposable
    public MyClass()
    {
        ++ClassInstances;
    }

    public void Dispose()
    {
        --ClassInstances;
    }

    private static new object _ClassInstancesLock;
    private static int _ClassInstances;
    private static int ClassInstances
    {
        get
        {
            lock (_ClassInstancesLock)
            {
                return _ClassInstances
            }
        }
    }

This is just a really rough sample, no tests for compilation; 0% guarantee for thread-safety (critical for this type of approach) and it leaves the door wide open for Dispose to be called, the instance counter to decrement, but for the object not to properly GC. To diagnose that bundle of joy you'll need, you guessed it, a professional profiler--or at least windbg.

这只是一个非常粗略的样本,没有编译测试; 0%保证线程安全(对于这种类型的方法至关重要)并且它使门敞开以便调用Dispose,实例计数器减少,但是对象不能正确GC。为了诊断你需要的那束快乐,你猜对了,一个专业的探测器 - 或至少是windbg。

Edit: I just noticed the very last line of your question and needed to say that my above approach, as shoddy and failure-prone as it is, is almost guaranteed to deceive and lie to you about the true number of instances if you're experiencing a leak. The best tool, IMO, for attacking these problems is ANTS Memory Profiler. Version 5 is a double-edge in that they broke Performance and Memory profiler into two seperate SKUs (used to be bundled together) but Memory Profiler 5.0 is absolutely lightning fast. Profiling these problems used to be slow as molases, but they've gotten around it somehome.

编辑:我刚刚注意到你问题的最后一行,并且需要说我的上述方法,如同粗制滥造和失败一样,几乎可以保证欺骗并欺骗你,如果你是真实的实例数量遇到泄漏。用于攻击这些问题的最佳工具IMO是ANTS Memory Profiler。版本5是双边缘,因为它们将性能和内存分析器分成两个单独的SKU(过去捆绑在一起),但Memory Profiler 5.0绝对闪电般快。分析这些问题过去常常像潮湿一样缓慢,但他们已经解决了一些问题。

Unless this is for a personal project with 0 intent of redistribution you should invest the few hundred dollars needed for ANTS--but by all means use it's trial period first. It's a great tool for exactly this kind of analysis.

除非这是针对具有重新分配意图的个人项目,否则您应该投入ANTS所需的几百美元 - 但无论如何都要首先使用它的试用期。对于这种分析来说,它是一个很好的工具。

#2


The only way I see to do this is without any form of instrumentation to use the CLR Profiling API to track object lifetimes. I'm not aware of any APIs available to the managed code to do the same thing, and, so far as I know, CLR doesn't keep the list of live objects anywhere (so even with profiler API you have to create the data structures for that yourself).

我看到这样做的唯一方法是没有任何形式的工具来使用CLR Profiling API来跟踪对象的生命周期。我不知道托管代码可以使用任何API来执行相同的操作,而且据我所知,CLR不会将实时对象列表保留在任何位置(因此即使使用分析器API,您也必须创建数据你自己的结构)。

VB.NET has a feature where it lets you track objects in debugger, but it actually emits additional code specifically for that (which basically registers all created objects in internal list of weak references). You could do that as well, using e.g. PostSharp to post-process your assemblies.

VB.NET有一个功能,它允许你跟踪调试器中的对象,但它实际上发出了专门用于它的附加代码(它基本上将所有创建的对象注册在弱引用的内部列表中)。您也可以使用例如PostSharp后处理您的程序集。