P/Invoke 内存资源处理方案

在使用 P/Invoke 调用本地代码时,正确处理内存资源至关重要,以避免内存泄漏和资源浪费。以下是几种常见的处理方案:

1. 基本内存处理

分配与释放

csharp

[DllImport("kernel32.dll")]
static extern IntPtr HeapAlloc(IntPtr hHeap, uint dwFlags, UIntPtr dwBytes);

[DllImport("kernel32.dll")]
static extern bool HeapFree(IntPtr hHeap, uint dwFlags, IntPtr lpMem);

// 使用示例
IntPtr ptr = HeapAlloc(IntPtr.Zero, 0, (UIntPtr)100);
// 使用内存...
HeapFree(IntPtr.Zero, 0, ptr);

使用 Marshal 类

csharp

// 分配内存
IntPtr ptr = Marshal.AllocHGlobal(100);

try
{
    // 使用内存...
}
finally
{
    // 释放内存
    Marshal.FreeHGlobal(ptr);
}

2. 自动释放方案

使用 SafeHandle

csharp

public class SafeMemoryHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    [DllImport("kernel32.dll")]
    private static extern bool CloseHandle(IntPtr handle);
    
    public SafeMemoryHandle() : base(true) { }
    
    protected override bool ReleaseHandle()
    {
        return CloseHandle(handle);
    }
}

// 使用
using (var handle = new SafeMemoryHandle())
{
    // 自动释放
}

使用 IDisposable 模式

csharp

public class NativeResourceWrapper : IDisposable
{
    private IntPtr _nativeResource;
    
    public NativeResourceWrapper()
    {
        _nativeResource = Marshal.AllocHGlobal(100);
    }
    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    
    protected virtual void Dispose(bool disposing)
    {
        if (_nativeResource != IntPtr.Zero)
        {
            Marshal.FreeHGlobal(_nativeResource);
            _nativeResource = IntPtr.Zero;
        }
    }
    
    ~NativeResourceWrapper()
    {
        Dispose(false);
    }
}

3. 复杂类型处理

结构体处理

csharp

[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
    public int Value;
    public float Number;
}

// 分配结构体内存
MyStruct myStruct = new MyStruct();
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyStruct)));

try
{
    Marshal.StructureToPtr(myStruct, ptr, false);
    // 使用...
}
finally
{
    Marshal.DestroyStructure(ptr, typeof(MyStruct));
    Marshal.FreeHGlobal(ptr);
}

字符串处理

csharp

[DllImport("mylib.dll", CharSet = CharSet.Auto)]
static extern void SomeFunction(string value);

// 或者手动处理
[DllImport("mylib.dll")]
static extern void SomeFunction(IntPtr value);

// 使用
string str = "Hello";
IntPtr ptr = Marshal.StringToHGlobalAnsi(str);
try
{
    SomeFunction(ptr);
}
finally
{
    Marshal.FreeHGlobal(ptr);
}

4. 最佳实践

  1. 始终释放分配的内存 - 使用 try/finally 或 using 语句确保资源释放

  2. 优先使用 SafeHandle - 提供更安全的资源管理方式

  3. 注意编码转换 - 字符串处理时注意 ANSI/Unicode 转换

  4. 考虑线程安全 - 如果资源可能被多线程访问,需要同步处理

  5. 记录资源所有权 - 明确哪些代码负责分配和释放资源

通过遵循这些方案,可以有效地管理 P/Invoke 调用中的内存资源,避免常见的内存泄漏问题。

你可能感兴趣的:(java,算法,开发语言)