Текущий архив: 2005.12.11;
Скачать: CL | DM;
ВнизПоясните пожалуйста работу с AWE на примере? Найти похожие ветки
← →
bodomic © (2005-11-17 21:55) [0]Привет всем!
У меня есть необходимость выделить для своей программы (для двух её массивов) очень много памяти, больше стандартных 2 Гб, желательно вообще 20-40 :)
Насколько я понял, это реально, и для этого надо использовать технологию AWE.
Никак не могу разобраться, как именно надо использовать набор функций, что писать в качестве параметров, как определить handle моего процесса хотя бы...
Кто-нибудь может пояснить на *конкретном* примере от и до, как мне выделить под массив данных много Гб памяти? Допустим, 40Гб подкачки я задал в Windows, разрешил пользователю фиксировать страницы в памяти, дальше как? :)
А то у меня чушь одна получается, точнее ничего не получается, а толковых примеров тоже ещё не нашёл :(
Спасибо
← →
Anatoly Podgoretsky © (2005-11-17 22:00) [1]Дельфи поддердивает только 2 гб
← →
bodomic © (2005-11-17 22:40) [2]Спасибо за быстрый ответ.
Хммм... я что-то не понял значит
http://podgoretsky.com/ftp/Docs/Delphi/Memory/awe/02-about.html
"AWE решает эту проблему путем разрешения приложению непосредственно адресовать гигантскую память, в то время как оно может использовать и обычную 32-х битную адресацию. AWE предоставляет для приложений возможность иметь под кеш более чем 4 Гб (при условии, что существует соответствующая физическая память)."
Неужели под физической памятью имеется ввиду сама оперативка, без файла подкачки? (по моим данным Windows XP, а тем более 2000, не больше 3 Гб оперативы понимают).
И что такое тогда "гигантская память"? 2Гб я и так забиваю, без всяких мудростей с AWE :)
← →
MBo © (2005-11-18 07:29) [3]Поскольку при работе с AWE, насколько я понимаю, все равно не обеспечивается одновременный доступ к офигенному адресному пространству, а придется по очереди переключать страницы, проще поступить по-другому - самому организовать на диске большой файл, и работать с его Memory-Mapped отображением.
← →
bodomic © (2005-11-18 09:59) [4]MBo, а можно тоже какой-нибудь пример?
Когда я читал про Memory-Mapping, я почему-то понял всё наоборот - что маппить файл можно только в объём доступной оперативы, а не добавлять к нему. Поэтому стал читать про AWE. А всё вон как оборачивается :)
← →
MBo © (2005-11-18 10:05) [5]>маппить файл можно только в объём доступной оперативы
Да, но это не большая проблема.
Вместо того, чтобы напрямую объявлять огромный массив, можно организовать доступ через свойство класса, а в методе доступа переключать MapViewOfFile на нужный кусок разумного размера, скажем, 64 мегабайта. Поскольку доступ к данным в большинстве случаев происходит более-менее последовательно, переключения не обязательно будут слишком частыми.
← →
bodomic © (2005-11-18 10:27) [6]Так. Если я что-то тут понял:
Если у меня массив NxN, то я мапплю единовременно только N элементов. Это разумно, я так пробовал писать/читать в файл, выходило дико медленно и объёмно, в оперативу те же типы почему-то компактнее умещаются. В пропорции 1:40 где-то Ж8-0.
Так тот же массив, который в оперативку отображается в 2Гб, на винт разложится этак на 80 Гб.
Т.е. мне нужно сделать класс, у которого будет метод, скажем MyArray.Get(i,j), который будет маппить MapViewofFile(i*N) в оперативку и доставать j-й элемент, сместившись на столько-то байт относительно текущей позиции? А заполнить этот массив я смогу аналогично через MyArray.Put?
P.S.
Очень хочется живого примера :)
Я обычно самообразовываюсь по пути "рабочий пример -> разжевывание его мной через хелп/доки -> рабочий как надо код" :)
← →
Leonid Troyanovsky © (2005-11-18 10:41) [7]
> bodomic © (18.11.05 10:27) [6]
> Очень хочется живого примера :)
> Я обычно самообразовываюсь по пути "рабочий пример -> разжевывание
> его мной через хелп/доки -> рабочий как надо код" :)
У Джефа Рихтера есть пример. Как раз с массивом.
Поищи Windows для профессионалов.
--
Regards, LVT.
← →
bodomic © (2005-11-18 11:03) [8]
> У Джефа Рихтера есть пример. Как раз с массивом.
Спасибо, качаю.
← →
MBo © (2005-11-18 13:28) [9]
type
TIntArr = array[Word] of Integer;
PIntArr = ^TIntArr;
TArr = class
constructor Create(const N: DWord);
destructor Destroy; override;
private
FPage: DWord;
FPageSize: DWord;
FileSize: Int64;
FileSizeLow, FileSizeHigh: DWord;
HMap: THandle;
PMap: PIntArr;
function GetElement(y, x: DWord): Integer;
procedure SetElement(y, x: DWord; const Value: Integer);
procedure SetPage(const APage: DWord);
public
property Element[y, x: DWord]: Integer read GetElement write SetElement;
default;
end;
constructor TArr.Create(const N: DWord);
var
FileHandle: THandle;
begin
FPageSize := (N * SizeOf(Integer) + 65535) and $FFFF0000;
FileSize := FPageSize * N;
FileSizeLow := FileSize and $FFFFFFFF;
FileSizeHigh := FileSize shr 32;
FileHandle := CreateFile(PChar("C:\Test.dat"),
GENERIC_READ + GENERIC_WRITE,
FILE_SHARE_WRITE,
nil, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0);
if FileHandle = INVALID_HANDLE_VALUE then
raise Exception.Create("Cannot create file ");
HMap := CreateFileMapping(FileHandle, nil, PAGE_READWRITE,
FileSizehigh, FileSizeLow, nil);
CloseHandle(FileHandle);
if HMap = 0 then
raise Exception.Create("Cannot map file");
SetPage(0);
end;
destructor TArr.Destroy;
begin
UnMapViewOfFile(PMap);
CloseHandle(HMap);
// to do: DeleteFile
inherited Destroy;
end;
function TArr.GetElement(y, x: DWord): Integer;
begin
if y <> FPage then
SetPage(y);
Result := PMap[x];
end;
procedure TArr.SetElement(y, x: DWord; const Value: Integer);
begin
if y <> FPage then
SetPage(y);
PMap[x] := Value;
end;
procedure TArr.SetPage(const APage: DWord);
var
FPos: Int64;
FPosLow, FPosHigh: DWord;
begin
FPage := APage;
FPos := FPage * FPageSize;
FPosLow := FPos and $FFFFFFFF;
FPosHigh := FPos shr 32;
PMap := MapViewOfFile(HMap, FILE_MAP_ALL_ACCESS, FPosHigh, FPosLow,
FPageSize);
if PMap = nil then
raise Exception.Create("Cannot map view of file");
end;
//----------------------
procedure TForm1.Button1Click(Sender: TObject);
begin
Arr := TArr.Create(1024);
Arr[0, 0] := 4;
Arr[1023, 1023] := 5;
Caption := IntToStr(Arr[0, 0]) + " " + IntToStr(Arr[1023, 1023]);
Arr.Free;
end;
← →
bodomic © (2005-11-18 22:16) [10]
> MBo © (18.11.05 13:28) [9]
Вот это ничего себе :)
Спасибо большое, буду разбираться с примером и с Рихтером.
Всем спасибо.
← →
bodomic © (2005-11-22 10:28) [11]
> MBo © (18.11.05 13:28) [9]
А вот такой вопрос странный выявился:
При использовании отображения файла в память страницы в файле подкачки после использования не освобождаются, и следовательно нарастает выделенная приложению память в файле подкачки (от чего и хотелось уйти :)) - когда дело доходит до 2 Гб, меня точно также выбрасывает с Out of Memory, как и при прямом использовании оперативы...
Вставка
if PMap <> nil then UnMapViewOfFile(PMap);
PMap:=nil; //это уже перестраховка бредовая :)
в начало TArr.SetPage не помогает.
Как грамотно освободить память?
Может быть на определённых этапах дестроить и создавать заново весь класс?
Или просто вместо PMap:=nil надо писать PMap.Free?
← →
MBo © (2005-11-22 14:25) [12]я при выделении SetPage в метод класса потерял вот что:
в SetPage надо вставить
UnMapViewOfFile(PMap);
Кроме того, в примере нерационально используется память при небольшой длине строк массива - под каждую строку отводится минимум 64К (гранулярность выделения памяти). СтОит модифицировать систему упаковки данных в зависимости от X-размерности.
← →
bodomic © (2005-11-22 17:15) [13]:)
Я пробовал UnMap..., не помогает, посмотрите мой пост.
Или надо UnMap делать сразу после Map? Это как-то выглядит нереально...
А про нерациональность я уже заметил, но меня пока это устраивает. Если припрёт, буду максимально рационализироваться, используя такие N, что N*sizeof(bla-bla)=64k.
Код у вас хороший, претензий нету :)
только вот память бы освободить :)
← →
MBo © (2005-11-22 17:51) [14]Очень странно. Вот в каком виде у меня сейчас SetPage. При запуске теста с закомментированным UnMap память (в диспетчере задач), естественно, программой отъедается, а с этой строкой - всего несколько десятков килобайт.
procedure TArr.SetPage(const APage: DWord);
var
FPos: Int64;
FPosLow, FPosHigh: DWord;
begin
FPage := APage;
FPos := FPage * FPageSize;
FPosLow := FPos and $FFFFFFFF;
FPosHigh := FPos shr 32;
UnMapViewOfFile(PMap);
PMap := MapViewOfFile(HMap, FILE_MAP_ALL_ACCESS, FPosHigh, FPosLow,
FPageSize);
if PMap = nil then
raise Exception.Create("Cannot map view of file");
end;
//test
procedure TForm1.Button1Click(Sender: TObject);
var
x, y: Integer;
t: DWord;
begin
Arr := TArr.Create(2048);
t := GetTickCount;
for y := 0 to 2047 do
for x := 0 to 511 do
Arr[y, x] := x;
Caption := IntToStr(Arr[0, 0]) + " " + IntToStr(Arr[511, 511]) + " " +
IntToStr(GetTickCount - t);
Arr.Free;
end;
← →
bodomic © (2005-11-22 19:06) [15]В диспетчере задач включена колонка Virtual memory? Он её поглощает.
Если без этой колонки смотреть, память тоже не особо расходуется, только пухнет и пухнет файл подкачки :)
← →
Defunct © (2005-11-23 04:39) [16]bodomic © (22.11.05 19:06) [15]
А почему бы вместо Map/UnMap не загружать блоки файла просто в статический массив? Фактически выполнять MemoryMapping самостоятельно.
подкреплю сказанное примером:type
TIntArr = array[Word] of Integer;
// PIntArr = ^TIntArr; <-- не требуется, т.к. предполагаем статический mapping
TArr = class
constructor Create(const N: DWord);
destructor Destroy; override;
private
FPage: DWord;
FPageSize: DWord;
{
FileSize: Int64;
FileSizeLow, FileSizeHigh: DWord;
}
FMappedFile : TFileStream;
FMap: TIntArr; // <-- changed
function GetElement(y, x: DWord): Integer;
procedure SetElement(y, x: DWord; const Value: Integer);
procedure SetPage(const APage: DWord);
public
property Element[y, x: DWord]: Integer read GetElement write SetElement;
default;
end;
constructor TArr.Create(const N: DWord);
begin
FMappedFile := TFileStream.Create( "C:\Test.dat", fmOpenReadWrite + fmShareExclusive );
FPageSize := (N * SizeOf(Integer) + 65535) and $FFFF0000;
SetPage(0);
end;
destructor TArr.Destroy;
begin
if Assigned( FMappedFile ) then
SetPage( 0 );
FMappedFile.Free;
inherited Destroy;
end;
function TArr.GetElement(y, x: DWord): Integer;
begin
if y <> FPage then
SetPage(y);
Result := FMap[x];
end;
procedure TArr.SetElement(y, x: DWord; const Value: Integer);
begin
if y <> FPage then
SetPage(y);
FMap[x] := Value;
end;
procedure TArr.SetPage(const APage: DWord);
var
FPos: Int64;
FPosLow, FPosHigh: DWord;
begin
FMappedFile.Position := FPos;
FMappedFile.Write( FMap, FPageSize ); // <-- сохранение пред. страницы
FPage := APage;
FPos := FPage * FPageSize;
FMappedFile.Read( FMap, FPageSize );
end;
//----------------------
var
Arr : TArr;
procedure TForm1.Button1Click(Sender: TObject);
begin
Arr := TArr.Create(1024);
Arr[0, 0] := 4;
Arr[1023, 1023] := 5;
Caption := IntToStr(Arr[0, 0]) + " " + IntToStr(Arr[1023, 1023]);
Arr.Free;
end;
2 MBO, за основу был взят твой класс.. надеюсь не будешь пинать ногами..
← →
Defunct © (2005-11-23 04:41) [17]блин.. а форматирование куда пропало?
← →
Джо © (2005-11-23 05:04) [18]
> [17] Defunct © (23.11.05 04:41)
> блин.. а форматирование куда пропало?
При вставке двойные пробелы в начале строки заменяются на один, а одинарные - съедаются. Увы :(
← →
bodomic © (2005-11-23 10:20) [19]Спасибо за идею, Defunct
Я с этого начинал :) Писал/читал в/из TFileStream. Правда, это было довольно наколенно написано, надо попробовать стащить ваш код :)
Однако чертовски интересно, неужели никак нельзя освободить занятые страницы? :( Они ведь ну ваще совсем никак мне не нужны после разового использования... Нелогично, блин.
Страницы: 1 вся ветка
Текущий архив: 2005.12.11;
Скачать: CL | DM;
Память: 0.51 MB
Время: 0.037 c