Управляемое использование памяти MemoryMappedFile.CreateViewStream()

Выделит ли MemoryMappedFile.CreateViewStream(0, len) управляемый блок памяти размером len или будет выделен меньший буфер, который действует как скользящее окно для неуправляемых данных?

Мне интересно, потому что я стремлюсь заменить промежуточный буфер для десериализации, которым сегодня является MemoryStream, что доставляет мне проблемы с большими наборами данных как из-за размера буфера, так и из-за фрагментации LOH.

Если внутренний буфер потока просмотра станет того же размера, то такое переключение не будет иметь смысла.

Изменить:

В ходе быстрого теста я нашел эти числа при сравнении MemoryStream с файлом MemoryMapped. Показания от GC.GetTotalMemory(true)/1024 и Process.GetCurrentProcess.VirtualMemorySize64/1024

Выделите поток памяти объемом 1 ГБ:

                     Managed           Virtual 
Initial:               81 kB        190 896 kB
After alloc:    1 024 084 kB      1 244 852 kB

Как и ожидалось, гиг как управляемой, так и виртуальной памяти. Теперь для MemoryMappedFile:

                     Managed           Virtual 
Initial:               81 kB        189 616 kB    
MMF allocated:         84 kB        189 684 kB
1GB viewstream allocd: 84 kB      1 213 368 kB
Viewstream disposed:   84 kB        190 964 kB

Итак, используя не очень научный тест, я предполагаю, что ViewStream использует только неуправляемые данные. Правильный?


person Anders Forsgren    schedule 21.06.2013    source источник


Ответы (2)


Такой ММФ не решит вашу проблему. Программа «бомбит» OOM, потому что в пространстве виртуальной памяти нет достаточно большой дыры, чтобы поместиться в нее. Вы все еще потребляете адресное пространство VM с MMF, как вы можете сказать.

Использование небольшого скользящего представления было бы обходным путем, но это ничем не отличается от записи в файл. Это то, что MMF делает, когда вы переназначаете представление, ему нужно сбросить грязные страницы на диск. Простая потоковая передача в FileStream является правильным обходным путем. Это по-прежнему использует оперативную память, кэш файловой системы помогает ускорить запись. Если у вас есть гигабайт оперативной памяти, что в наши дни нетрудно найти, то запись в FileStream — это просто копирование из памяти в память. Очень быстро, 5 гигабайт/сек и выше. Файл лениво записывается в фоновом режиме.

Попытки слишком усердно хранить данные в памяти непродуктивны в Windows. Частные данные в памяти поддерживаются файлом подкачки и будут записываться в этот файл, когда Windows потребуется ОЗУ для других процессов. И перечитайте, когда вы получите к нему доступ снова. Это медленно, чем больше памяти вы используете, тем хуже становится. Как и в любой операционной системе с виртуальной памятью с подкачкой по запросу, разница между диском и памятью невелика.

person Hans Passant    schedule 21.06.2013
comment
Я, должно быть, что-то совершенно неправильно понял, 32-битная программа .NET, которая выдает исключение из-за нехватки памяти, по моему опыту, взорвалась, потому что она достигла потолка ~ 1,3-1,5 ГБ общего использования управляемой памяти или ( как обычно) фрагментирует LOH и пытается выделить большой массив, например, при использовании больших потоков памяти. - person Anders Forsgren; 21.06.2013
comment
Звучит хорошо, если Windows I/O делает недолговечный временный файл по существу копией в памяти, я попробую. О чем мне нужно подумать при использовании FileStream для этого, чтобы избежать его сброса на диск? - person Anders Forsgren; 21.06.2013
comment
Нет, это ограничение ВМ, неуправляемые распределения имеют не меньшее значение. Вы не можете контролировать, сколько оперативной памяти используется для данных FileStream. Вы не можете повлиять на это, кроме как косвенно, через объем данных, которые вы записываете, и какие другие процессы выполняются на машине, которые также используют кеш. - person Hans Passant; 21.06.2013
comment
Я надеялся использовать огромное количество виртуальных машин, доступных вне процесса (для 32-битного приложения в 64-битной ОС), но, к сожалению, мне нужно иметь возможность искать в этих данных. А выделение ViewStream/ViewAccessor будет выделять память в процессе, который жрет лимит в 2 Гб. Поэтому я уберу требование поиска/буферизации (т. е. однопроходную сериализацию) или буду использовать FileStream в качестве временного буфера. Спасибо. - person Anders Forsgren; 24.06.2013

учитывая пример на http://msdn.microsoft.com/en-us/library/system.io.memorymappedfiles.memorymappedfile.aspx мне кажется, что вы получаете скользящее окно, по крайней мере, это то, что я интерпретирую при чтении примера.

Вот пример для удобства:

    using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;

class Program
{
    static void Main(string[] args)
    {
        long offset = 0x10000000; // 256 megabytes 
        long length = 0x20000000; // 512 megabytes 

        // Create the memory-mapped file. 
        using (var mmf = MemoryMappedFile.CreateFromFile(@"c:\ExtremelyLargeImage.data", FileMode.Open,"ImgA"))
        {
            // Create a random access view, from the 256th megabyte (the offset) 
            // to the 768th megabyte (the offset plus length). 
            using (var accessor = mmf.CreateViewAccessor(offset, length))
            {
                int colorSize = Marshal.SizeOf(typeof(MyColor));
                MyColor color;

                // Make changes to the view. 
                for (long i = 0; i < length; i += colorSize)
                {
                    accessor.Read(i, out color);
                    color.Brighten(10);
                    accessor.Write(i, ref color);
                }
            }
        }
    }
}

public struct MyColor
{
    public short Red;
    public short Green;
    public short Blue;
    public short Alpha;

    // Make the view brigher. 
    public void Brighten(short value)
    {
        Red = (short)Math.Min(short.MaxValue, (int)Red + value);
        Green = (short)Math.Min(short.MaxValue, (int)Green + value);
        Blue = (short)Math.Min(short.MaxValue, (int)Blue + value);
        Alpha = (short)Math.Min(short.MaxValue, (int)Alpha + value);
    }
}
person b_meyer    schedule 21.06.2013
comment
Я не вижу в этом примере, будет ли создание accessor например. буфер размером 64 КБ для чтения блока размером 512 МБ, или это действительно выделенный буфер размером 512 МБ. - person Anders Forsgren; 21.06.2013
comment
мне кажется буфер 512мб который выделен - person b_meyer; 21.06.2013