2010-02-15 2 views
3

Иногда возникает проблема с исчерпанием памяти, когда она фрагментирована.Найти большой свободный блок памяти

Возможно ли найти самый большой свободный блок памяти? Я использую Delphi 2007 с FastMM. Разработка на Windows XP работает приложение на Windows 2003.

С уважением

EDIT: Я мог бы добавить информацию о том, что приложение работает на сервере с ГБ памяти на сервере x64 Windows 2003 32. Но приложение представляет собой 32-разрядное приложение, поэтому теоретическая максимальная выделенная память для каждого экземпляра составляет 2 ГБ. Многие экземпляры запускаются сразу. Я не думаю, что это полная физическая память. Я думаю, при запуске приложение получило 32-битное виртуальное пространство памяти. Это может быть слишком фрагментировано во время выполнения.

Я также нашел метод FastGetHeapStatus, который возвращает THeapStatus с некоторыми полями для свободной памяти. Возможно, я смогу использовать их.

EDIT2: Я нашел это How to get the largest available continues memory block. Код C, но, возможно, он может быть переведен в Delphi.

+2

Небольшая коррекция: в 64-битных версиях ОС вы получить полный диапазон адресов 4 ГБ для 32-битных процессов. Возможно, этот процесс не сможет его использовать (из-за того, что используемые типы подписей используются в программах управления памятью), но предел отличается от 32-разрядной ОС. У AFAIR Delphi * есть проблемы с этим. – mghie

+0

Да, delphi использует множество знаковых значений везде в RTL –

ответ

4

Это перевод на Delphi код, который вы хотели:

function GetLargestFreeMemRegion(var AAddressOfLargest: pointer): LongWord; 
var 
    Si: TSystemInfo; 
    P, dwRet: LongWord; 
    Mbi: TMemoryBasicInformation; 
begin 
    Result := 0; 
    AAddressOfLargest := nil; 
    GetSystemInfo(Si); 
    P := 0; 
    while P < LongWord(Si.lpMaximumApplicationAddress) do begin 
    dwRet := VirtualQuery(pointer(P), Mbi, SizeOf(Mbi)); 
    if (dwRet > 0) and (Mbi.State and MEM_FREE <> 0) then begin 
     if Result < Mbi.RegionSize then begin 
     Result := Mbi.RegionSize; 
     AAddressOfLargest := Mbi.BaseAddress; 
     end; 
     Inc(P, Mbi.RegionSize); 
    end else 
     Inc(P, Si.dwPageSize); 
    end; 
end; 

Вы можете использовать его как это:

procedure TForm1.FormCreate(Sender: TObject); 
var 
    BaseAddr: pointer; 
    MemSize: LongWord; 
begin 
    MemSize := GetLargestFreeMemRegion(BaseAddr); 
    // allocate dynamic array of this size 
    SetLength(fArrayOfBytes, MemSize - 16); 

    Caption := Format('Largest address block: %u at %p; dynamic array at %p', 
    [MemSize, BaseAddr, pointer(@fArrayOfBytes[0])]); 
end; 

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

6

Нет, это «maxavail» в старом Turbo Pascal, в часто запрашиваемой функции, но, к сожалению, это бесполезно понятие в многопользовательской, многозадачной среды

heapmanager может знать самый большой блок в памяти он сохраняет себя, но обычно это будет небольшим, так как большие куски напрямую выделяются из (и возвращаются) в окна.

И схемы постепенной попытки выделения больших блоков не удастся из-за того, что ОС будет предоставлять запросы, даже если это означает, что для него требуется обмен файлами (что вам не нужно). То же самое для трюков, которые пытаются раздобыть такие значения с помощью вызовов windows api.

Вся защищенная среда режима имеет в качестве основы общий доступ к памяти, и каждое приложение использует столько, сколько необходимо. Игнорируя это и делая вид, что все по-прежнему похоже на Dos, вы получите только массивные жалобы от людей, которые запускают сразу несколько приложений.

Если ваше приложение действительно зависит от этого, сделайте его настройкой конфигурации (сколько памяти выделяется при запуске для чего-либо) с безопасным (маленьким) значением по умолчанию. Если это ДЕЙСТВИТЕЛЬНО важно, столкнитесь с этим пользователем во время установки.

Можно, конечно же, всегда ставить значения по умолчанию с помощью эвристических попыток, совершив несколько вызовов winapi и предполагая, что никаких других приложений не запускается. Но всегда оставляйте конечное решение с пользователем, SPECIALLY для серверных приложений.

3

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

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

Основными параметрами, которые я могу видеть, являются: пользовательские распределители памяти, что-то, что связано с AWE (см. Ниже) или перестраивает стратегию распределения памяти в приложении.

Вариант 1: Пользовательские памяти распределители

распределители Пользовательские памяти не являются редкостью в кругах C и C++. Возможно, вы сможете реализовать нечто подобное. Две возможностей открыты для вас:

  • Построить Распределитель памяти с механизмом, который пытается объединить соседние свободные блоки в один большой блок (вы можете запустить это как часть пытается оправиться от неудачного выделения памяти). Это может позволить вам прозрачно управлять памятью, если приложение не должно быть известно. Реализация этого будет сложной и технической, но, вероятно, возможна.

    Главное преимущество этого подхода состоит в том, что он является единственным, который не требует от вас изменения существующего кода приложения. Недостатком является то, что он не гарантированно работает; все же возможно, что операция слияния может не консолидировать блок памяти, достаточно большой для выполнения запроса. Операция слияния также может привести к значительным паузам в ответе приложения во время его запуска.

  • Возможно, вам потребуется создать приложение таким образом, чтобы можно было уплотнять структуру данных. Это потребует от вас поддержки дескрипторов, которые поддерживают перемещаемые объекты, т. Е. Механизм двойной косвенности. Я предполагаю, что существует, вероятно, одно или довольно небольшое количество различных структур данных, которые вызывают эту проблему фрагментации, поэтому можно установить в любую другую работу по реорганизации в вашем приложении.

Вариант 2: PAE

Windows, делает средство поддержки непосредственно манипулировать MMU, и есть несколько возможностей, где это может относиться к вашему приложению. Это, безусловно, потребует явной поддержки архитектуры от вашего приложения, но дает возможность использовать пул памяти, который намного превышает 2 ГБ.

На серверных версиях Windows просмотрите PAE, который поддерживается API's, что позволяет вам вручную манипулировать MMU системы и переквалифицировать куски памяти. Это может быть полезным для вас в один из двух способов

  • Вы можете построить менеджер для структуры данных, таким образом, что использует этот механизм в качестве неотъемлемой части управления данными.

  • Если вы можете поместить элементы в своей структуре данных на границы страниц, вы можете использовать это как способ консолидации памяти.

Однако такой подход потребует от вас реорганизовать ваше приложение таким образом, что ссылки на объект имел достаточно информации для управления процессом явного подкачки в (возможно, своего рода наложения менеджера с механизмом прокси для объектов, с помощью этой системы). Это означает, что любое решение, включающее PAE, не является заменой для FastMM - вам нужно будет изменить приложение, чтобы явно поддерживать PAE.

Однако прокси-механизм такого рода может означать, что эта подсистема может быть относительно прозрачной для клиентов. Помимо накладных расходов на управление косвенностью и оверлеями (что может быть или не быть существенной проблемой) прокси могут быть практически неотличимы от оригинального API. Такой подход будет работать лучше всего для относительно небольшого количества крупных и тяжелых объектов с минимальным взаимосоединением - каноническое приложение для этого - кэширование диска. Прокси должны были оставаться в фиксированном месте в памяти, причем более крупные объекты просматривались через механизм наложения. YMMV.

Вариант 3: Исправлена ​​проблема в источнике

Одной из возможностей является то, что ваша стратегия распределения объекта может быть оптимизирована из кода приложения (возможно, из пулов объектов, выделенных в объеме, а затем управлять из приложения). Это может позволить вам иметь дело с фрагментацией памяти из вашего приложения, не пытаясь переписать диспетчер памяти.

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

+0

1) Слияние смежных блоков на самом деле не дает многого, если блоки неподвижны. Собственный memmanager может быть desparate решением, но вам, вероятно, нужно добавить знания о шаблоне доступа приложений к менеджеру, чтобы сделать значительно лучше, чем fastmm. 2) PAE не помогает, потому что компилятор Delphi 32, а не 64-битный, и предполагает 32-разрядные указатели линии. Схемы, например, не сохраняя более низкие 4 бита, будут прерывать арифметику указателя. Факторизующая интенсивность битов памяти до 64-битных DLL-файлов FPC является более здравым решением. Я бы выбрал вариант 3 в сочетании с распределением наибольшего блока, необходимого при запуске. –

+0

Спасибо за ответ. Мы не создаем собственного диспетчера памяти, я в этом уверен. Надеемся, что это 64-разрядный компилятор Delphi, так как сегодня память дешевая. Тем временем я добавил в приложение память, чтобы пользователь мог наблюдать за ситуацией. В случае EOutOfMemory предлагаю перезапустить ... :) –

Смежные вопросы