固定長メモリマネージャ2
というわけでModern C++ Design*1を引っ張り出してきて、起きた頭で書き直し。
type TFixedMemoryManager = object private Memory: Pointer; UnitSize: Cardinal; First: Pointer; Last: Pointer; public constructor Initialize(AUnitSize: Cardinal); destructor Finalize; function Allocate: Pointer; procedure Free(AUnit: Pointer); end;
{ TFixedMemoryManager }
function TFixedMemoryManager.Allocate: Pointer;
var
NewCommitSize: Integer;
Next, I: Pointer;
begin
if First = Last then
begin
NewCommitSize := UnitSize * 1024;
if VirtualAlloc(Last, NewCommitSize, MEM_COMMIT, PAGE_READWRITE) = nil then
OutOfMemoryError;
Result := First;
Inc(Cardinal(Last), NewCommitSize);
Inc(Cardinal(First), UnitSize);
I := First;
while Cardinal(I) < Cardinal(Last) do
begin
Next := Pointer(Cardinal(I) + UnitSize);
PPointer(I)^ := Next;
I := Next;
end;
end
else
begin
Result := First;
First := PPointer(Result)^;
end;
end;
destructor TFixedMemoryManager.Finalize;
var
Commited: Cardinal;
begin
Commited := Cardinal(Last) - Cardinal(Memory);
if Commited <> 0 then
VirtualFree(Memory, Commited, MEM_DECOMMIT);
if Memory <> nil then
begin
{$IFOPT C+}
if not VirtualFree(Memory, 0, MEM_RELEASE) then RaiseLastOSError;
{$ELSE}
VirtualFree(Memory, 0, MEM_RELEASE);
{$ENDIF}
end;
end;
procedure TFixedMemoryManager.Free(AUnit: Pointer);
begin
PPointer(AUnit)^ := First;
First := AUnit;
end;
constructor TFixedMemoryManager.Initialize(AUnitSize: Cardinal);
const
MaxLogicalLimitation = 1024 * 1024 * 1024; {1GB!}
var
LogicalLimitation: Cardinal;
begin
UnitSize := AUnitSize;
if AUnitSize < SizeOf(Pointer) then
UnitSize := SizeOf(Pointer);
First := nil;
Last := nil;
LogicalLimitation := MaxLogicalLimitation;
repeat
Memory := VirtualAlloc(nil, LogicalLimitation, MEM_RESERVE, PAGE_READWRITE);
if Memory <> nil then Break;
LogicalLimitation := LogicalLimitation div 2;
if LogicalLimitation < AUnitSize then
OutOfMemoryError;
until False;
First := Memory;
Last := Memory;
end;速い!圧倒的に速い!
ヒープ関数や上の実装の1/10以上速く動きます。
*1:この本初めて役に立ったかも…