要调用需要IntPtr的方法,使用/ unsafe或Marshal.AllocHGlobal会更好吗?

时间:2009-11-05 18:55:12

标签: c# marshalling unsafe fixed intptr

我有一个类,在整个应用程序期间会有一些持久化的实例。这些对象将需要调用一个dll方法,该方法从现有的float []缓冲区附加数据,并将完整数据集传递给接受IntPtr(float数组)的DLL方法,每秒几次。将其作为非托管代码更好:



    class PersistentThing : IDisposable {
        readonly IntPtr _floats = Marshal.AllocHGlobal(sizeof(float) * ArraySize);

        public void DoFrequentAction() {
            // Append data from a buffer to the memory space.
            var floatOffsetPtr = new IntPtr(_floats.ToInt32() + _floatsIndex * sizeof(float));
            Marshal.Copy(_buffer, _bufferIndex, floatOffsetPtr, _bufferCount);

            // Call a DLL method with with memory pointer
            CallDllMethod(_floats);
        }

        // Need to dispose the unmanaged memory
        public void Dispose() {
            Marshal.FreeHGlobal(_floats);
        }
    }

或者使用不安全的标签并修复会更好吗?


    class PersistentThing2 {
        readonly float[] _floats = new float[ArraySize];

        public unsafe void DoFrequentAction() {
            // Append data from a buffer to the memory space.
            Array.Copy(_buffer, _bufferIndex, _floats, _floatsIndex, _bufferCount);

            // Call a DLL method with with memory pointer
            fixed (float* floatsPtr = _floats) {
                CallDllMethod((IntPtr)floatsPtr);
            }
        }
    }

是否有任何优势,不必在编译器中使用“unsafe”标签?元帅级实际上是否更“安全”?哪种方法通常具有更好的性能?

我倾向于前者,只是因为GC在清理内存空间时不必担心_floats(可能非常大)。这是一个合理的担忧吗?建议是否取决于ArraySize的大小?

2 个答案:

答案 0 :(得分:3)

在这两种情况下,您都在调用原生的,不安全的代码。

我更喜欢第二种选择 - 它更干净,更容易理解,更明显。它也不会强制您使用IDisposable来收集阵列。

答案 1 :(得分:2)

我最终了解到两种解决方案都很好。性能大致相同,GC不会对第二个解决方案产生影响,因为对象将被分配给大对象堆并且从未移动,或者很快被提升到垃圾收集器上的第二代并且很少移动