Гость
Map
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Простейший менеджер памяти на базе VirtualAlloc / 25 сообщений из 90, страница 1 из 4
23.02.2022, 23:25
    #40136192
Наталья87
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Необходима реализация простейшего менеджера памяти на базе VirtualAlloc. Чтобы не использовать выделение памяти средствами Delphi или FastMM, а обращаться напрямую к операционной системе. Потому что в приложении много багов, которые портят память. Выделение кусков средствами операционной системе должно помочь вызывать Access Violation если что-то пойдет не так.

Как я понимаю, выглядит это примерно так:
https://www.gunsmoker.ru/2009/01/blog-post.html

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
type
  // В старых Delphi
  TMemoryManager = record
    GetMem: function(Size: Integer): Pointer;
    FreeMem: function(P: Pointer): Integer;
    ReallocMem: function(P: Pointer; Size: Integer): Pointer;
  end;
 
  // В новых Delphi
  TMemoryManagerEx = record
    { Базовая (обязательная) функциональность }
    GetMem: function(Size: Integer): Pointer;
    FreeMem: function(P: Pointer): Integer;
    ReallocMem: function(P: Pointer; Size: Integer): Pointer;
    { Дополнительная (опциональная) функциональность }
    AllocMem: function(Size: Cardinal): Pointer;
    RegisterExpectedMemoryLeak: function(P: Pointer): Boolean;
    UnregisterExpectedMemoryLeak: function(P: Pointer): Boolean;
  end;



но примера реализации этих методов на базе VirtualAlloc найти не могу ...
...
Рейтинг: 0 / 0
23.02.2022, 23:58
    #40136195
Dmitry Arefiev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
SafeMM
...
Рейтинг: 0 / 0
24.02.2022, 00:01
    #40136196
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Наталья87
Выделение кусков средствами операционной системе должно помочь вызывать Access Violation если что-то пойдет не так.
Не поможет. VirtualAlloc выделяет память страницами. Размер страницы - 4096 байт. Т.е. если вы запросили 10 байт, а обратились к 3000, то никто вам ничего не скажет.
...
Рейтинг: 0 / 0
24.02.2022, 00:10
    #40136197
Наталья87
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
_Vasilisk_
Наталья87
Выделение кусков средствами операционной системе должно помочь вызывать Access Violation если что-то пойдет не так.
Не поможет. VirtualAlloc выделяет память страницами. Размер страницы - 4096 байт. Т.е. если вы запросили 10 байт, а обратились к 3000, то никто вам ничего не скажет.


Тут дело скорее в том - чтобы один кусок программы не мог портить память, выделенную другим куском программы.

В этом случае VirtualAlloc поможет.

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

В случае FastMM или других разделяемых менеджеров памяти фактически любой баг в каком-нибудь потоке или таймере может испортить важную память основного потока и приложение упадёт.
...
Рейтинг: 0 / 0
24.02.2022, 00:16
    #40136198
Наталья87
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Dmitry Arefiev
SafeMM


Работает под Delphi 7. Но увы, проект с ним вообще не запускается под Delphi XE8. И еще - он какой-то медленный очень.
Там много функций для отладки - но тут речь не про отладку а про Release-приложение. Есть в приложении баги или нет - другой вопрос - но нужно минимизировать вероятность падения Release-приложения по причине багов.
...
Рейтинг: 0 / 0
24.02.2022, 00:20
    #40136199
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Наталья87
Наоборот, есть еще идея - обматывать выделяемые куски памяти "одеялом". То есть выделять вначале пару килобайт, потом запрашиваемый объем памяти, умноженный на 3 (рабочая область посередине), потом еще пару килобайт. Чтобы глючный код мог немного промахиваться и это не приводило к падению приложения.
А, понял. Цель не исправить ошибки, а завуалировать их
...
Рейтинг: 0 / 0
24.02.2022, 01:01
    #40136201
Наталья87
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
_Vasilisk_
Наталья87
Наоборот, есть еще идея - обматывать выделяемые куски памяти "одеялом". То есть выделять вначале пару килобайт, потом запрашиваемый объем памяти, умноженный на 3 (рабочая область посередине), потом еще пару килобайт. Чтобы глючный код мог немного промахиваться и это не приводило к падению приложения.
А, понял. Цель не исправить ошибки, а завуалировать их


Исправлять можно у себя на компьютере. Пользователю зачем ошибки видеть?
...
Рейтинг: 0 / 0
24.02.2022, 01:59
    #40136204
Наталья87
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Кроме SafeMM ни один менеджер памяти не пережил такой код:

Код: pascal
1.
2.
3.
4.
5.
6.
var
   xxx: array of byte;
begin
   setlength(xxx, 100);
   for ii:=100 to 200000 do
      xxx[ii] := 90;



В случае с SafeMM выдало Access Violation, но приложение не упало!
Но SafeMM слишком медленный, поэтому и хотелось бы реализации на базе стандартных функций VirtualAlloc.
Я думаю, поскольку память VirtualAlloc выделяется системой - подобные ошибки или пройдут незамеченными или вызовут Access Violation, но не будут валить приложение.
...
Рейтинг: 0 / 0
24.02.2022, 02:11
    #40136205
энди
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Наталья87
_Vasilisk_
пропущено...
А, понял. Цель не исправить ошибки, а завуалировать их


Исправлять можно у себя на компьютере. Пользователю зачем ошибки видеть?


Отсутствие ошибки порождает у пользователя уверенность что программа работает в штатном режиме. Если выдается адекватное сообщение об ошибке с кнопкой послать отчет разработчику то это нормально.
Вообще странный подход конечно, ну да Ваше дело.
...
Рейтинг: 0 / 0
24.02.2022, 02:51
    #40136206
Наталья87
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Все дело в том, что SafeMM не работает с модулями IdHttp, IdFtp.
Экспериментальным путем было проверено, что дело не в моем проекте, а в этих модулях.

Есть вот такой код - который нужно переписать с HeapAlloc на VirtualAlloc.



Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
UNIT WindowsMM;
INTERFACE
USES Windows;
IMPLEMENTATION    
type
   TMInteger = Integer;
   SIZE_T = Integer;
var
   gHeap: THandle;

function NewGetMem({$IFNDEF D2010}DataSize: TMInteger{$ELSE}DataSize: NativeInt{$ENDIF}): Pointer;
begin
   if DataSize<=0 then begin
      Result := nil;
      Exit;
   end;
//   Result := VirtualAlloc(nil, DataSize,MEM_COMMIT, PAGE_READWRITE);
   Result := HeapAlloc(gHeap, 0, DataSize);
end;


function NewFreeMem(DataPtr: Pointer): Integer;
begin
   if DataPtr=nil then begin
      Result := 0;
      Exit;
   end;
   HeapFree(gHeap, 0, DataPtr);
//   VirtualFree(DataPtr, 0, MEM_RELEASE);
   Result := 0;
end;

function NewReallocMem(DataPtr: Pointer; {$IFNDEF D2010}DataSize: TMInteger{$ELSE}DataSize: NativeInt{$ENDIF}): Pointer;
begin
   if (DataPtr=nil) or (DataSize<=0) then begin
      Result := nil;
      Exit;
   end;
   Result := HeapRealloc(gHeap, 0, DataPtr, DataSize);
end;




const
   HeapCompatibilityInformation = 0;
   HeapEnableTerminationOnCorruption = 1;
   HEAP_LFH = 2;
var
   HeapSetInformation: function(
      HeapHandle: THandle;
      HeapInformationClass: ULONG;
      HeapInformation: pointer;
      HeapInformationLength: SIZE_T
   ): BOOL; stdcall;

   

procedure InitLowFragmentationHeap(AHeap :THandle);
var
   vModule :HMODULE;
   vHeapInformation :ULONG;
begin
   vModule := GetModuleHandle(kernel32);
   if vModule<>0 then
      @HeapSetInformation := GetProcAddress(vModule, 'HeapSetInformation');
   if Assigned(HeapSetInformation) then begin
      vHeapInformation := HEAP_LFH;
      HeapSetInformation(AHeap, HeapCompatibilityInformation, @vHeapInformation, SizeOf(vHeapInformation));
   end;
end;



const
   DebugMemMgr: TMemoryManager = (
      GetMem    : NewGetMem;
      FreeMem   : NewFreeMem;
      ReallocMem: NewReallocMem
   );
var
   OldMemMgr: TMemoryManager;
   ManagerInstalled: Boolean = False;

procedure InstallMemoryManager;
begin
   if not ManagerInstalled then begin
      GetMemoryManager(OldMemMgr);
      SetMemoryManager(DebugMemMgr);
      gHeap := GetProcessHeap;
      InitLowFragmentationHeap(gHeap);
      ManagerInstalled := True;
   end;
end;

procedure DeinstallMemoryDebugManager;
begin
   if ManagerInstalled then begin
      SetMemoryManager(OldMemMgr);
      ManagerInstalled := False;
   end;
end;



INITIALIZATION
   InstallMemoryManager;
FINALIZATION
  DeinstallMemoryDebugManager;
END.
...
Рейтинг: 0 / 0
24.02.2022, 11:54
    #40136225
Наталья87
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Ладно, попробую переделать SafeMM. Идея в том, чтобы выделять большой защищённый блок в 64Кб на каждый запрос по выделению. памяти.
...
Рейтинг: 0 / 0
24.02.2022, 16:27
    #40136275
Наталья87
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Код менеджера после переделывания. Максимально минимизированный и на базе SafeMM. Большой проект на этом менеджере работает и запускается на Delphi 7.

Пустой проект с 1 формой на Delphi XE8 тоже работает. Но стоит подключить 2 модуля

USES IdFtp, IdHttp;

и проект не запускается - завершаясь с ошибкой Runtime Error 216 at00405353
Иногда выходит
access violation at address 00000000

То же самое с исходным SafeMM - стоит подключить модули

USES IdFtp, IdHttp;

и при запуске приложения с 1 формой выходит ошибка

access violation at address 00000000

Как заставить SafeMM работать с родными Delphi-модулями IdHttp, IdFtp или навскидку есть ли очевидные баги в модуле ниже?




Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
UNIT WndMM;
INTERFACE
{$IF RTLVersion >= 18.0}
   {$DEFINE MEMORY_MANAGER_EX}
{$IFEND}
              
function SafeGetMem(size: integer): pointer;
function SafeFreeMem(p: pointer): integer;
function SafeReallocMem(p: pointer; size: integer): pointer;
function SafeAllocMem(size: cardinal): pointer;

const
{$IFDEF MEMORY_MANAGER_EX}
   SafeMemoryManager: TMemoryManagerEx = (
      GetMem: SafeGetMem;
      FreeMem: SafeFreeMem;
      ReallocMem: SafeReallocMem;
      AllocMem: SafeAllocMem;
      RegisterExpectedMemoryLeak: nil;
      UnregisterExpectedMemoryLeak: nil;
   );
{$ELSE}
   SafeMemoryManager: TMemoryManager = (
      GetMem: SafeGetMem;
      FreeMem: SafeFreeMem;
      ReallocMem: SafeReallocMem;
   );
type
   TMemoryManagerEx = TMemoryManager;
{$ENDIF}

IMPLEMENTATION
USES Windows;
type
   PBlockInfo = ^TBlockInfo;
   TBlockInfo = record
      start: pointer;
      size: cardinal;
   end;
var
   fCritical: TRTLCriticalSection;

function offset(const p: pointer; const addon: integer): pointer;
begin
   result := pointer( cardinal(p) + addon );
end;

function SafeGetMem(size: integer): pointer;
var
   block: PBlockInfo;
   size2, BlockSize: cardinal;
begin
   size2 := size + sizeof(TBlockInfo);

   BlockSize := size2 div 4096;
   if size2 mod 4096>0 then inc(BlockSize);
   BlockSize := BlockSize*4096;

   block := VirtualAlloc(nil, BlockSize, MEM_COMMIT, PAGE_READWRITE);
   block.start := offset(block, sizeof(TBlockInfo));
   block.size := size;

   result := block.start;
end;

function SafeAllocMem(size: cardinal): pointer;
begin
   result := SafeGetMem(size);
end;

function min(const i1, i2: integer): integer;
begin
   result := i1;
   if i2<result then result := i2;
end;

function SafeFreeMem(p: pointer): integer;
begin
   p := offset(p, -sizeof(TBlockInfo));
   VirtualFree(p, 0, MEM_RELEASE);
   result := 0;
end;

function SafeReallocMem(p: pointer; size: integer): pointer;
var
   block: PBlockInfo;
   BlockSize: integer;
begin
   block := offset(p, -sizeof(TBlockInfo));
   result := SafeAllocMem(size);
   BlockSize := min(block.size, size);
   Move(p^, result^, BlockSize);
   SafeFreeMem(p);
end;

INITIALIZATION
   InitializeCriticalSection(fCritical);
FINALIZATION
   DeleteCriticalSection(fCritical);
END.





Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
UNIT WndMMInstall;
INTERFACE
IMPLEMENTATION
USES WndMM;
var
  FOldManager: TMemoryManagerEx;

procedure InstallSafeMemoryManager;
begin
   GetMemoryManager(FOldManager);
   SetMemoryManager(SafeMemoryManager);
end;

procedure UninstallSafeMemoryManager;
begin
   SetMemoryManager(FOldManager);
end;

INITIALIZATION
   InstallSafeMemoryManager;
FINALIZATION
   UninstallSafeMemoryManager;
END.
...
Рейтинг: 0 / 0
24.02.2022, 16:42
    #40136278
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Наталья87
есть ли очевидные баги в модуле ниже?

Вангую, что нужно сделать заглушки для:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
   SafeMemoryManager: TMemoryManagerEx = (
      GetMem: SafeGetMem;
      FreeMem: SafeFreeMem;
      ReallocMem: SafeReallocMem;
      AllocMem: SafeAllocMem;
      RegisterExpectedMemoryLeak: nil;
      UnregisterExpectedMemoryLeak: nil;
   );
...
Рейтинг: 0 / 0
24.02.2022, 17:12
    #40136282
Наталья87
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Kazantsev Alexey
Наталья87
есть ли очевидные баги в модуле ниже?

Вангую, что нужно сделать заглушки для:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
   SafeMemoryManager: TMemoryManagerEx = (
      GetMem: SafeGetMem;
      FreeMem: SafeFreeMem;
      ReallocMem: SafeReallocMem;
      AllocMem: SafeAllocMem;
      RegisterExpectedMemoryLeak: nil;
      UnregisterExpectedMemoryLeak: nil;
   );



Спасибо, помогло. И SafeMM после данного дополнения чудесным образом заработал.
...
Рейтинг: 0 / 0
25.02.2022, 17:39
    #40136467
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Наталья87
Экспериментальным путем было проверено, что дело не в моем проекте, а в этих модулях.
Точно вам говорю - это ошибка компилятора.
...
Рейтинг: 0 / 0
28.02.2022, 00:18
    #40136644
Наталья87
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
_Vasilisk_
Наталья87
Экспериментальным путем было проверено, что дело не в моем проекте, а в этих модулях.
Точно вам говорю - это ошибка компилятора.


Интересный момент еще. Если использовать данный менеджер памяти (и выделять блоки кратные 4 Кб по каждому чиху - даже если требуется 10 байт) - при примерно 150 Мб занятой оперативной памяти (проверка Диспетчером задач на Win Xp с 4 Гб оперативы) выскакивает ошибка "Out of Memory" - хотя памяти свободной еще вагон. Видимо, есть какие-то ограничения операционной системы на количество выделяемых блоков, в какой-то момент функция VirtualAlloc перестает выделять память.
...
Рейтинг: 0 / 0
28.02.2022, 00:21
    #40136646
Наталья87
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
_Vasilisk_
Наталья87
Экспериментальным путем было проверено, что дело не в моем проекте, а в этих модулях.
Точно вам говорю - это ошибка компилятора.


Вообще странно, что SafeMM поставляется без этих методов для Delphi XE+, хотя заявлено, что он должен работать на Delphi XE+. Хотя если принять, что это все-таки сторонний менеджер памяти и писали его люди, а устроен он довольно сложно внутри - в нём могут быть и ошибки и недоработки, как в любой программе.
...
Рейтинг: 0 / 0
28.02.2022, 00:32
    #40136647
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Наталья87
Видимо, есть какие-то ограничения операционной системы на количество выделяемых блоков, в какой-то момент функция VirtualAlloc перестает выделять память.

Это называется фрагментацией адресного пространства.
...
Рейтинг: 0 / 0
28.02.2022, 11:21
    #40136665
GunSmoker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Наталья87
при примерно 150 Мб занятой оперативной памяти (проверка Диспетчером задач на Win Xp с 4 Гб оперативы) выскакивает ошибка "Out of Memory" - хотя памяти свободной еще вагон

Оперативная память не имеет никакого отношения к выделенной памяти в программе. В оперативной памяти программа может занимать как меньше памяти, чем она выделила (чаще всего), так и больше.

Если вы хотите смотреть за потреблением памяти вашей программы, то в диспетчере задач выберите Вид / Выбрать столбцы и поставьте галку на "Объём виртуальной памяти".

Также рекомендую: https://www.gunsmoker.ru/2011/04/windows-spin-off.html
...
Рейтинг: 0 / 0
28.02.2022, 11:29
    #40136667
GunSmoker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
У VirtualAlloc по умолчанию гранулярность выделения памяти - 64 кб . Это значит, что в 2 Гб адресном пространстве этой функцией можно выделить не более 32'768 блоков.
...
Рейтинг: 0 / 0
28.02.2022, 11:32
    #40136668
GunSmoker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Наталья87
Вообще странно, что SafeMM поставляется без этих методов для Delphi XE+, хотя заявлено, что он должен работать на Delphi XE+. Хотя если принять, что это все-таки сторонний менеджер памяти и писали его люди, а устроен он довольно сложно внутри - в нём могут быть и ошибки и недоработки, как в любой программе.

SafeMM - это просто экспериментальная демка, proof-of-concept. Уж тем более не предполагается, что его будут использовать в релизе.
...
Рейтинг: 0 / 0
28.02.2022, 11:34
    #40136669
GunSmoker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
_Vasilisk_
Не поможет. VirtualAlloc выделяет память страницами. Размер страницы - 4096 байт. Т.е. если вы запросили 10 байт, а обратились к 3000, то никто вам ничего не скажет.

Не обязательно использовать память с начала страницы. Если цель отловить overflow, то логический блок должен заканчиваться ровно на конце физического, а начинаться где-то в середине этой 4к страницы.
...
Рейтинг: 0 / 0
28.02.2022, 12:00
    #40136673
GunSmoker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
Наталья87
Но SafeMM слишком медленный, поэтому и хотелось бы реализации на базе стандартных функций VirtualAlloc.

VirtualAlloc - это функция ядра Windows. Любой вызов ядра - это очень медленно, поскольку происходит переключение пользовательского режима и режима ядра. И с этим ничего сделать нельзя, никакое переписывание кода здесь не поможет. По сути, SafeMM - это и есть минимальная обёртка к VirtualAlloc, ничего особо больше он не делает.

Поэтому общепринятая практика как раз выделять память одним большим куском, а потом логически делить его внутри пользовательского режима, не переключаясь в режим ядра.
...
Рейтинг: 0 / 0
28.02.2022, 14:57
    #40136699
Наталья87
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
GunSmoker
Наталья87
Но SafeMM слишком медленный, поэтому и хотелось бы реализации на базе стандартных функций VirtualAlloc.

VirtualAlloc - это функция ядра Windows. Любой вызов ядра - это очень медленно, поскольку происходит переключение пользовательского режима и режима ядра. И с этим ничего сделать нельзя, никакое переписывание кода здесь не поможет. По сути, SafeMM - это и есть минимальная обёртка к VirtualAlloc, ничего особо больше он не делает.

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


Да, так и получилось в итоге.

Через мой менеджер памяти на базе VirtualAlloc работает также медленно (а то и еще медленнее), чем через SafeMM. При этом и памяти жрет больше, чем SafeMM (и приложение по причине OutOfMemory поэтому вылетает даже на 64-разрядных сборках). Т. к. SafeMM хоть и использует агрессивно VirtualAlloc и VirtualProtect, выделяя в разы больше памяти, чем нужно - но все же для мелких блоков он не использует VirtualAlloc.

Попробую еще для интереса не по 4 Кб, а сразу по 64 Кб выделять. Хуже судя по всему не будет - просто Диспетчер Задач будет отображать реальный объем потребляемой памяти.
...
Рейтинг: 0 / 0
28.02.2022, 15:07
    #40136701
Наталья87
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Простейший менеджер памяти на базе VirtualAlloc
GunSmoker
_Vasilisk_
Не поможет. VirtualAlloc выделяет память страницами. Размер страницы - 4096 байт. Т.е. если вы запросили 10 байт, а обратились к 3000, то никто вам ничего не скажет.

Не обязательно использовать память с начала страницы. Если цель отловить overflow, то логический блок должен заканчиваться ровно на конце физического, а начинаться где-то в середине этой 4к страницы.


Для отлова ошибок есть уже готовые SafeMM и FastMM. Но первый слишком медленный и скорее для Debug, а не для Release, хотя с задачей не допустить падения программы и повреждения памяти кривым кодом справляется прекрасно. Второй как-то плохо защищает память от кривого кода .

Цель немного другая для Release-сборок. И состоит не только в том, чтобы отловить ошибки.

Цель именно в том, чтобы ошибки в программе не приводили к повреждению памяти, последующим глюкам а то и падению приложения (у клиентов на Release-сборке).

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

Чтобы не тормозило и не потребляло горы памяти - очевидно, делать надо это не с помощью VirtualAlloc, а с помощью HeapAlloc. Если просто выделять больше памяти, чем нужно и не ловить ошибки - замедление получается всего на 30% - при этом я полагаю, это должно защищать от порчи памяти.

И еще - было принято решение включить Range Check Error и Overflow Check. На Release сборках в том числе. По сути они не так уж сильно замедляют работу программы, как SafeMM, а толку в плане защиты памяти на практике от них немало.

Если можно - поясните, пожалуйста, в чем я не права и заблуждаюсь.
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Простейший менеджер памяти на базе VirtualAlloc / 25 сообщений из 90, страница 1 из 4
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]