如何计算两个检查点之间创建的实例数

时间:2013-12-10 17:16:57

标签: c#

我想做点什么:

ObjectRecorder.Start();
//Do stuff here ...
ObjectRecorder.Stop();

//And get the result
List<Object> result = ObjectRecorder.GetAll();
//or even 
ObjectRecorder.GetNumberInstanceCreated();

我想要实现的目标

我正在使用BlockingCollection并分析我的应用程序我看到TryTake正在创建对象internaly。由于我经常调用此方法,我想通过单元测试公开错误,然后实现新的ImprovedBlockingQueue并看到问题已解决。

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

您要实现的目标非常难以实现,因为您希望在进程运行时检查进程的托管内存。这样的操作可能非常昂贵,我真的认为应该采用不同的单元测试方法,例如,您可以尝试使用GC.GetTotalMemory方法来跟踪整体内存使用情况。如果是单独的单元测试,那就足够了。

尽管如此,我还是想提一下的可能性,以便在令人惊讶的Microsoft.Diagnostics.Runtime库(处于预发布阶段)的帮助下实现您的目标。您可以附加到正在运行的进程并检查Managed Heap:

public static void GetStats(ClrRuntime runtime)
{
    ClrHeap heap = runtime.GetHeap();
    var stats = heap.EnumerateObjects()
                    .Select(obj => new 
                    {
                        Type = heap.GetObjectType(obj),
                        ObjectAddress = obj
                    })
                    .GroupBy(g => g.Type,
                             g => g.Type.GetSize(g.ObjectAddress))
                    .Select(gr => new
                    {
                        Name = gr.Key.Name,
                        Count = gr.Count(),
                        Size = gr.Sum(x => (int)x)
                    })
                    .Where(t => !t.Name.StartsWith("System.") &&
                                !t.Name.StartsWith("Microsoft.") &&
                                !t.Name.Equals("Free"))
                    .ToList();
    Console.WriteLine("---------- Start ----------");
    foreach (var item in stats)
        Console.WriteLine("{0} {} {2}", item.Size, item.Count, item.Name);
}

样本用法:

var process = Process.GetCurrentProcess();
using (var dataTarget = DataTarget.AttachToProcess(process.Id, 1000, AttachFlag.Passive))
{
    string dacLocation = dataTarget.ClrVersions[0].TryGetDacLocation();
    ClrRuntime runtime = dataTarget.CreateRuntime(dacLocation);
    GetStats(runtime);

    List<User> list = new List<User>();
    Enumerable.Range(1, 1000).ToList().ForEach(i => list.Add(new User() { Age = i }));

    Thread.Sleep(10000);

    GetStats(runtime);
}

但是:为了附加到自身,只有AttachFlag.Passive可能被描述为:

  

执行“被动”附加,这意味着实际上没有附加调试器   到目标进程。该过程未暂停,因此查询   快速更改数据(例如GC堆的内容或   除非用户暂停,否则callstacks)将高度不一致**   通过其他方式处理。

因此,在这种情况下,可能很难获得有关托管堆的确定性统计数据。

答案 1 :(得分:0)

这可能会有所帮助:

class ObjectRecorder
{
    static List<ObjectRecorder> valuse=new List<ObjectRecorder>();

    bool record = false;

    public ObjectRecorder()
    {
        //your code
        if (record){ valuse.Add(this); }
    }

    public void StartRecording(){ record = true; }

    public void StopRecording(){ record = false; }

    public void ResetRecording()
    {
        valuse = new List<ObjectRecorder>();
    }

    public List<ObjectRecorder> GetAll()
    {
        return valuse;
    }
}