You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现快速指针扫描?.NET指针扫描性能优化求助

问题描述

我正在开发一款工具,用于在程序更新后自动查找指针。目前遇到的问题是:单独搜索特定4/8字节值速度尚可,但指针路径扫描的速度无法达标。

以下是我基于VirtualQueryEx实现的内存区域搜索代码:

public List<MemoryScanResult> Search(MemoryRegion region, byte[] targetValue)
{
    var results = new List<MemoryScanResult>();
    var buffer = region.Cache;
    
    switch (targetValue.Length)
    {
        case 8:
            CheckBufferUnsignedLong(BitConverter.ToUInt64(targetValue));
            break;
        case 4:
            CheckBufferUnsignedInt(BitConverter.ToUInt32(targetValue));
            break;
        default:
            throw new NotSupportedException();

    }
    
    void CheckBufferUnsignedInt(uint value)
    {
        unsafe
        {
            fixed (byte* pBuffer = buffer)
            {
                var itemSize = buffer!.Length / 4;
                var values = (uint*)pBuffer;
                for (var i = 0; i < itemSize; i++)
                {
                    if (value != values[i])
                        continue;

                    var foundResult = new MemoryScanResult
                                      {
                                          Address = region.BaseAddress + (i * itemSize),
                                          FoundAtBase = region.AllocationBase == _applicationMemory.Address
                                      };

                    results!.Add(foundResult);
                }
            }
        }
    }

    void CheckBufferUnsignedLong(ulong value)
    {
        unsafe
        {
            fixed (byte* pBuffer = buffer)
            {
                var itemSize = buffer!.Length / 8;
                var values = (ulong*)pBuffer;
                for (var i = 0; i < itemSize; i++)
                {
                    if (value != values[i])
                        continue;

                    var foundResult = new MemoryScanResult
                                      {
                                          Address = region.BaseAddress + (i * itemSize),
                                          FoundAtBase = region.AllocationBase == _applicationMemory.Address
                                      };

                    results!.Add(foundResult);
                }
            }
        }
    }

    return results;
}

该应用拥有1.9GB可读可写内存,划分为3500个非空内存区域。使用4个工作线程通过Parallel.ForEach运行上述函数,扫描全部1.9GB内存耗时约500ms,结果数量正确。但进行指针扫描时,若从目标值地址前0x1000位置开始搜索,找到首个结构体指针可能耗时4分钟以上。

我了解到Cheat Engine具备同类功能且速度极快,其源码可查,但我未能理清它的优化机制,不确定是否已触及.NET的性能上限。

Cheat Engine无需缓存整个堆,指针扫描时内存占用远低于我的实现,推测它是按需读取内存区域;若我采用该方式,搜索耗时会增至900ms。

补充:切换为Release模式后,缓存缓冲区的扫描耗时降至160-200ms,但最坏情况下用4个工作线程查找1个指针仍需1.7分钟。仅向集合中添加17条结果就会增加50ms耗时,我开始考虑脱离.NET实现核心逻辑,再封装为.NET调用的接口。

请问我遗漏了哪些优化技巧?

优化建议
  • 削减GC与内存分配开销
    你提到添加17条结果就增加50ms耗时,核心问题在于List<MemoryScanResult>的动态扩容以及MemoryScanResult实例的频繁创建。可以:

    • 预分配List容量:根据内存区域大小估算可能的结果数,初始化List时指定capacity,避免扩容时的内存拷贝。
    • 将MemoryScanResult改为结构体:如果该类型仅用于数据存储,值类型无需GC回收,能大幅减少内存分配开销。
    • 使用对象池:若必须用类,提前创建一批MemoryScanResult实例复用,避免频繁创建销毁。
  • 重构指针扫描逻辑,减少冗余操作
    当前代码是先收集所有匹配目标值的地址,再进行指针验证(判断是否指向目标区域),这会产生大量无效候选。参考Cheat Engine的思路:

    • 边扫描边验证:在找到匹配的4/8字节值时,先判断该值是否属于目标进程的有效内存范围,再直接读取该地址的内容,检查是否接近目标指针地址。如果不符合条件,直接跳过,不加入结果集合,从根源减少后续处理量。
    • 过滤无效区域:提前排除不可能包含有效指针的内存区域(比如大小不足4/8字节的区域、无读写权限的区域,或者内容全为0/固定垃圾值的区域)。
  • 优化内存读取策略

    • 按需读取+批量验证:无需缓存整个内存区域,而是分块读取(比如按页读取),读取后立即进行指针验证,验证完成后释放该块内存,降低内存占用的同时减少缓存带来的额外开销。
    • 替换高效内存读取API:直接调用原生的ReadProcessMemory批量读取内存,减少.NET封装层的开销;同时确保读取操作是对齐的,避免非对齐访问的性能损耗。
  • unsafe代码与循环优化

    • 用指针递增替代数组索引:在unsafe循环中,直接通过指针自增遍历(如uint* ptr = values; while (ptr < values + itemSize) { ...; ptr++; }),减少数组索引计算的额外开销。
    • 提前计算重复判断:比如FoundAtBase的判断region.AllocationBase == _applicationMemory.Address,可以在循环外计算一次布尔值,循环内直接复用,避免重复的地址比较。
  • 并行调度优化

    • 调整并行度:将Parallel.ForEach的MaxDegreeOfParallelism设置为CPU核心数(而非固定4个),让调度器更合理地分配线程。
    • 避免共享集合竞争:如果后续需要合并多线程的结果,每个线程使用独立的List存储结果,最后再一次性合并,避免使用线程安全集合带来的锁开销。
  • 考虑原生代码实现核心逻辑
    如果上述优化仍无法达标,确实可以用C++编写核心的扫描与验证逻辑,编译为原生DLL后通过P/Invoke供.NET调用。原生代码在内存操作、循环执行上的效率远高于.NET,能彻底规避CLR的GC、JIT等开销限制。

内容的提问来源于stack exchange,提问作者TyCobb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 20:05:39