如何在不修改源码的前提下,运行时统计类型X的对象实例数?
统计不同程序集下类型X的运行时实例总数(无需修改目标代码)
纯反射无法直接获取CLR中所有存活的对象实例,以下是几种适配不同场景的可行方案:
方案1:使用.NET诊断API(堆快照统计)
适合.NET Core/.NET 5+版本,通过获取进程堆快照实现一次性统计,无需修改目标代码,实现成本低。
实现步骤:
- 引用NuGet包:
Microsoft.Diagnostics.NETCore.Client和Microsoft.Diagnostics.Runtime - 编写统计代码:
using Microsoft.Diagnostics.Runtime; public static int CountTypeXInstances() { using var dataTarget = DataTarget.AttachToProcess( System.Diagnostics.Process.GetCurrentProcess().Id, TimeSpan.FromSeconds(5), AttachFlag.Passive); ClrRuntime runtime = dataTarget.ClrVersions.First().CreateRuntime(); // 替换为X的完整命名空间+类型名 ClrType typeX = runtime.Heap.GetTypeByName("YourNamespace.X"); if (typeX == null) return 0; int count = 0; foreach (ClrObject obj in runtime.Heap.EnumerateObjects()) { if (obj.Type == typeX) count++; } return count; }
注意事项:
- 堆快照会短暂暂停进程,适合非实时的一次性统计场景
- 若X类型存在于多个程序集,可通过
typeX.Module.AssemblyName区分筛选 - 需确保类型的完整名称(含命名空间)准确无误
方案2:CLR探查器(实时统计)
适用于所有.NET版本(包括.NET Framework),通过编写CLR探查器拦截对象分配事件,实现实时精准统计。
核心逻辑:
实现ICorProfilerCallback接口的ObjectAllocated方法,每次对象分配时检查类型是否为X,匹配则累加计数。同时可通过弱引用跟踪实例存活状态,避免统计已回收对象。
关键要点:
- 需用C++编写探查器并注册到CLR运行时
- 可拦截所有程序集中的X类型实例分配事件
- 实现复杂度较高,需熟悉CLR Profiling API底层机制
方案3:动态代码注入(实时统计)
利用AOP框架动态注入构造函数钩子,跟踪X类型实例的创建,适合允许动态修改运行时代码的场景。
实现示例(基于Harmony库):
- 引用NuGet包:
Lib.Harmony - 编写跟踪代码:
using HarmonyLib; using System.Collections.Generic; using System.Reflection; public static class InstanceTracker { private static readonly List<WeakReference> _xInstances = new List<WeakReference>(); public static int GetXInstanceCount() { lock (_xInstances) { // 清理已被GC回收的实例引用 _xInstances.RemoveAll(r => !r.IsAlive); return _xInstances.Count; } } public static void HookTypeXConstructors() { var harmony = new Harmony("XInstanceTracker"); // 遍历所有程序集,查找类型X var typeXList = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(asm => asm.GetTypes()) .Where(t => t.Name == "X") // 可替换为FullName提升精准度 .ToList(); foreach (var typeX in typeXList) { // Hook所有构造函数(含私有构造) var ctors = typeX.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (var ctor in ctors) { harmony.Patch(ctor, postfix: new HarmonyMethod(typeof(InstanceTracker).GetMethod("PostfixCtor"))); } } } private static void PostfixCtor(object __instance) { lock (_xInstances) { _xInstances.Add(new WeakReference(__instance)); } } }
使用方式:
程序启动时调用InstanceTracker.HookTypeXConstructors()完成钩子注入,后续随时调用InstanceTracker.GetXInstanceCount()获取当前存活实例数。
注意事项:
- 动态注入需要足够权限,沙箱等受限环境可能无法运行
- 需覆盖所有程序集中的X类型,确保无遗漏构造函数
- 用WeakReference存储实例,避免内存泄漏导致实例无法被GC回收
内容的提问来源于stack exchange,提问作者DuckQueen
相关产品推荐
相关产品推荐

