Sdílet prostřednictvím


Unmanaged memory management in C# without P/Invoke

.NET CLR provides great managed memory management. But there are occasions when we want to manage memory on our own. And yes, CLR allows a C# program to call native code via P/Invoke. There is nothing wrong with P/Invoke until we need to call a native API many times in a performance critical code section. Graph Engine provides a set of lightweight wrappers for the commonly-used C memory management functions, such as malloc, free, memcpy, memmove, and memcmp.

To use these functions, create a “Graph Engine Application Project” in Visual Studio and add the namespace “Trinity.Core.Lib”. Compared with their P/Invoked counterparts, the Graph Engine wrappers can usually give us a little bit performance edge. Try out the following code snippet:

using System;

using System.Diagnostics;

using System.Runtime.InteropServices;

using System.Text;

using System.Threading.Tasks;

using Trinity;

using Trinity.Core.Lib;

namespace GraphEngineApp1

{

    unsafe internal class Program

    {

        static void Main(string[] args)

        {

            int count = 1000000;

            void* src = Memory.malloc(300);

            void* dst = Memory.malloc(300);

            Stopwatch sw = Stopwatch.StartNew();

            for (int i = 0; i < count; i++)

            {

                Memory.memcpy(dst, src, 300);

            }

            sw.Stop();

            Console.WriteLine(sw.ElapsedMilliseconds);

            Memory.free(src);

            Memory.free(dst);

        }

    }

}

Now replace the “Memory.memcpy(dst, src, 300) ” with the P/Invoked version, and run again. On my machine, the GE wrapper version takes 14 ms, while the P/Invoked version takes 25 ms.

Use P/Invoke if its overhead is negligible for your application. Consider giving the GE wrappers a shot if the overhead caused by P/Invoke starts to bother you.