.Net Core быстрое выделение памяти и нулевая инициализация памяти (кроссплатформенное решение) - PullRequest
0 голосов
/ 25 сентября 2019

Существует ли быстрый способ выделения и инициализации нуля большого блока памяти с помощью .Net Core?

Ищите решение, которое работает как на платформах Windows, так и на Linux.

Кажется,самый быстрый метод в Windows - вызвать функцию kernel32 HeapAlloc через PInvoke, это выделяет и обнуляет блок памяти объемом 1 ГБ менее чем за 2 миллисекунды.

Однако я не нашел способа добиться подобных результатов в Linuxпока только использую .Net Core.

Я попробовал метод Marshal.AllocHGlobal, который не обнуляет память, а затем обнуляет память с помощью Marshal.Copy, чтобы скопировать массив нулевых байтов в память, ноэто дает низкую производительность, то есть 800 миллисекунд по сравнению с 2 миллисекундами, указанными выше.

Для моего приложения распределение и обнуление должны быть выполнены менее чем за 10 миллисекунд.

Обеспечивает ли .Net Core перекрестную передачуAPI платформы, который дал бы такую ​​же производительность, как Windows HeapAlloc или что-то вроде функции C calloc?

Тестовый код ниже:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace MemoryApp
{
    class Program
    {
        static void Main(string[] args)
        {
            const int sizeBytes = 1_000_000_000;

            Console.WriteLine($"Allocating memory of size: {sizeBytes} bytes.");

            const int totalAttempts = 20;

            for (int i = 0; i < totalAttempts; i++)
            {
                var stopwatch = Stopwatch.StartNew();

                var allocatedMemory = new AllocatedMemory(sizeBytes);

                stopwatch.Stop();

                Console.WriteLine($"Allocated memory in {stopwatch.ElapsedTicks} ticks ({stopwatch.ElapsedMilliseconds} milliseconds).");

                allocatedMemory.Dispose();
            }

            Console.ReadLine();
        }
    }

    public unsafe class AllocatedMemory : IDisposable
    {
        public byte* MemoryAddress { get; }

#if USE_WINDOWS_HEAP
        private IntPtr _heapPtr;
#else
        private IntPtr _memoryPtr;
#endif

        public AllocatedMemory(int sizeInBytes)
        {
#if USE_WINDOWS_HEAP
            var heapFlags = HeapFlags.HEAP_GENERATE_EXCEPTIONS | HeapFlags.HEAP_ZERO_MEMORY;

            _heapPtr = Heap.HeapCreate(heapFlags, 0, 0);
            MemoryAddress = (byte*)Heap.HeapAlloc(_heapPtr, heapFlags, (uint)sizeInBytes);
#else
            // Memory allocated but not zeroed
            _memoryPtr = Marshal.AllocHGlobal((IntPtr)sizeInBytes);

            // Zero the memory
            Marshal.Copy(new byte[sizeInBytes], 0, _memoryPtr, sizeInBytes);
            MemoryAddress = (byte*)_memoryPtr;
#endif
        }

        ~AllocatedMemory()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (MemoryAddress != null)
                {
#if USE_WINDOWS_HEAP
                    Heap.HeapDestroy(_heapPtr);
#else
                    Marshal.FreeHGlobal(_memoryPtr);
#endif
                }
            }
        }
    }

#if USE_WINDOWS_HEAP
    public class Heap
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr HeapCreate(HeapFlags flOptions, uint dwInitialsize, uint dwMaximumSize);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr HeapAlloc(IntPtr hHeap, HeapFlags dwFlags, uint dwSize);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool HeapDestroy(IntPtr hHeap);
    }

    [Flags]
    public enum HeapFlags
    {
        HEAP_NO_SERIALIZE = 0x1,
        HEAP_GENERATE_EXCEPTIONS = 0x4,
        HEAP_ZERO_MEMORY = 0x8
    }
#endif
}

1 Ответ

0 голосов
/ 25 сентября 2019

В C # 7 .Net ввел новые конструкции для работы с памятью, которые включают в себя Span и Memory

Span определяется как ref-структура, ограниченная выделением только в стеке, то есть уменьшает некоторые потенциальные варианты использованиянапример, хранить его как поле в классе.Но вы можете обойти это, используя другой тип памяти

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...