如何优化加速C#中P/Invoke原生调用(DeviceIoControl场景)性能
版主注:我认为这不是重复问题,因为我已经尝试过下述多个已提及的解决方案。
有没有办法可以加速这个调用?我已经遵循了微软的相关指南,完成了以下操作:
- 添加了
SuppressUnmanagedCodeSecurity特性 - 将相关代码放在名为
UnsafeNativeMethods.cs的文件中 - 为方法存根定义了特定类型
相关方法代码
[DllImport("kernel32.dll")] [SuppressUnmanagedCodeSecurity] public static extern bool DeviceIoControl( IntPtr hDevice, uint IoControlCode, [In] MemoryManager.MemOperation InBuffer, int nInBufferSize, [Out] byte[] OutBuffer, uint nOutBufferSize, ref int pBytesReturned, IntPtr Overlapped );
MemOperation结构体定义(推测为需要封送的输入缓冲区)
public struct MemOperation { public int Pid; public int UserPid; public int Size; public int protection_mode; public int allocation_type; public IntPtr Addr; public IntPtr WriteBuffer; [MarshalAs(UnmanagedType.LPWStr)] public string module_selection; }
调用示例
public UnsafeNativeMethods.MEMORY_BASIC_INFORMATION QueryVirtualMemory(IntPtr address) { var memOperation = new MemOperation(); byte[] buffer = new byte[48]; // 8 + 8 + 4 + 8 + 4 + 4 + 4 MEMORY_BASIC_INFORMATION memOperation.Pid = this.Pid; memOperation.Addr = address; int bytes = 0; bool res = UnsafeNativeMethods.DeviceIoControl(this.Handle, CtlCode(0x00000022, this.IOCTL_QUERY, 2, 0), memOperation, Marshal.SizeOf(memOperation), buffer, (uint)buffer.Length, ref bytes, IntPtr.Zero); return GetStructure<UnsafeNativeMethods.MEMORY_BASIC_INFORMATION>(buffer); }
性能分析器显示P/Invoke是我的热点路径。我的应用运行速度已经达到了我认为C#能实现的上限,但由于应用需要执行极多内存操作,几乎三分之一的执行时间都消耗在P/Invoke上。我希望尽可能削减这部分耗时,允许使用不安全方案。
我曾尝试编写DeviceIoControl的封装函数从C++ DLL导入,但没有产生任何优化效果,表现和之前完全一致,相关代码如下:
devicecontrol.cpp
#include <iostream> #include "DeviceControl.h" bool __cdecl DeviceIoRequestWrapper(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlappedk) { return DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlappedk); }
devicecontrol.h
#pragma once #include <Windows.h> extern "C" { __declspec(dllexport) bool __cdecl DeviceIoRequestWrapper( HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlappedk); }
我当前使用的是.NET 6.0和最新版本的C#。
我还尝试了对输出缓冲区的修改方案:
public unsafe UnsafeNativeMethods.MEMORY_BASIC_INFORMATION QueryVirtualMemory(IntPtr address) { var memOperation = new MemOperation(); byte* buffer = stackalloc byte[48]; memOperation.Pid = this.Pid; memOperation.Addr = address; int bytes = 0; bool res = UnsafeNativeMethods.DeviceIoControl(this.Handle, CtlCode(0x00000022, this.IOCTL_QUERY, 2, 0), memOperation, Marshal.SizeOf(memOperation), (IntPtr)buffer, 48, ref bytes, IntPtr.Zero); return GetStructure<UnsafeNativeMethods.MEMORY_BASIC_INFORMATION>(buffer); }
修改后的GetStructure实现如下:
public static unsafe T GetStructure<T>(byte* bytes) where T: unmanaged { T structure = *(T*)bytes; return structure; }
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

