我想做点什么:
ObjectRecorder.Start();
//Do stuff here ...
ObjectRecorder.Stop();
//And get the result
List<Object> result = ObjectRecorder.GetAll();
//or even
ObjectRecorder.GetNumberInstanceCreated();
我想要实现的目标
我正在使用BlockingCollection
并分析我的应用程序我看到TryTake正在创建对象internaly。由于我经常调用此方法,我想通过单元测试公开错误,然后实现新的ImprovedBlockingQueue
并看到问题已解决。
有什么想法吗?
答案 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;
}
}