固定長メモリマネージャ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:この本初めて役に立ったかも…