mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-05 00:48:05 +02:00
281 lines
6.4 KiB
ObjectPascal
281 lines
6.4 KiB
ObjectPascal
{
|
|
*****************************************************************************
|
|
This file is part of the Lazarus Component Library (LCL)
|
|
|
|
See the file COPYING.modifiedLGPL.txt, included in this distribution,
|
|
for details about the license.
|
|
*****************************************************************************
|
|
|
|
Author: Mattias Gaertner
|
|
|
|
Abstract:
|
|
Defines TLCLMemManager, which is the base class for various
|
|
memory managers in the lcl and its interfaces.
|
|
An own memory manager is somewhat faster and makes debugging and
|
|
profiling easier.
|
|
}
|
|
unit LCLMemManager;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, Math;
|
|
|
|
type
|
|
PLCLMemManagerItem = ^TLCLMemManagerItem;
|
|
TLCLMemManagerItem = record
|
|
Next: PLCLMemManagerItem;
|
|
end;
|
|
|
|
{ memory manager template }
|
|
|
|
TLCLMemManager = class
|
|
private
|
|
procedure SetMaxFreeRatio(NewValue: integer);
|
|
procedure SetMinFree(NewValue: integer);
|
|
protected
|
|
FFirstFree: PLCLMemManagerItem;
|
|
FFreeCount: integer;
|
|
FCount: integer;
|
|
FMinFree: integer;
|
|
FMaxFreeRatio: integer;
|
|
FAllocatedCount: int64;
|
|
FFreedCount: int64;
|
|
procedure DisposeItem(AnItem: PLCLMemManagerItem);
|
|
function NewItem: PLCLMemManagerItem;
|
|
procedure FreeFirstItem; virtual;
|
|
public
|
|
property MinimumFreeCount: integer read FMinFree write SetMinFree;
|
|
property MaximumFreeCountRatio: integer
|
|
read FMaxFreeRatio write SetMaxFreeRatio; // in one eighth steps
|
|
property Count: integer read FCount;
|
|
property FreeCount: integer read FFreeCount;
|
|
property AllocatedCount: int64 read FAllocatedCount;
|
|
property FreedCount: int64 read FFreedCount;
|
|
procedure Clear;
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
|
|
{ TLCLNonFreeMemManager - a memory manager for records without freeing }
|
|
|
|
TLCLEnumItemsMethod = procedure(Item: Pointer) of object;
|
|
|
|
TLCLNonFreeMemManager = class
|
|
private
|
|
FItemSize: PtrInt;
|
|
FItems: TFPList;
|
|
FCurItem: Pointer;
|
|
FEndItem: Pointer;
|
|
FCurSize: PtrInt;
|
|
FFirstSize: PtrInt;
|
|
FMaxItemsPerChunk: PtrInt;
|
|
public
|
|
ClearOnCreate: boolean;
|
|
property ItemSize: PtrInt read FItemSize;
|
|
property MaxItemsPerChunk: PtrInt read FMaxItemsPerChunk write FMaxItemsPerChunk;
|
|
procedure Clear;
|
|
constructor Create(TheItemSize: integer);
|
|
destructor Destroy; override;
|
|
function NewItem: Pointer;
|
|
procedure EnumerateItems(const Method: TLCLEnumItemsMethod);
|
|
end;
|
|
|
|
{ TExtMemoryStream }
|
|
|
|
TExtMemoryStream = class(TMemoryStream)
|
|
protected
|
|
function Realloc(var NewCapacity: PtrInt): Pointer; override;
|
|
public
|
|
property Capacity;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
{$IFOpt R+}{$Define RangeChecksOn}{$Endif}
|
|
|
|
{ TLCLMemManager }
|
|
|
|
procedure TLCLMemManager.Clear;
|
|
begin
|
|
while FFirstFree<>nil do begin
|
|
FreeFirstItem;
|
|
inc(FFreedCount);
|
|
end;
|
|
FFreeCount:=0;
|
|
end;
|
|
|
|
constructor TLCLMemManager.Create;
|
|
begin
|
|
inherited Create;
|
|
FFirstFree:=nil;
|
|
FFreeCount:=0;
|
|
FCount:=0;
|
|
FAllocatedCount:=0;
|
|
FFreedCount:=0;
|
|
FMinFree:=100000;
|
|
FMaxFreeRatio:=8; // 1:1
|
|
end;
|
|
|
|
destructor TLCLMemManager.Destroy;
|
|
begin
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TLCLMemManager.DisposeItem(AnItem: PLCLMemManagerItem);
|
|
begin
|
|
if AnItem<>nil then begin
|
|
if (FFreeCount<FMinFree) or (FFreeCount<((FCount shr 3)*FMaxFreeRatio)) then
|
|
begin
|
|
// add ANode to Free list
|
|
//AddItemToFreeList(AnItem);
|
|
inc(FFreeCount);
|
|
end else begin
|
|
// free list full -> free the ANode
|
|
//FreeItem(AnItem);
|
|
{$R-}
|
|
inc(FFreedCount);
|
|
{$IfDef RangeChecksOn}{$R+}{$Endif}
|
|
end;
|
|
dec(FCount);
|
|
end;
|
|
end;
|
|
|
|
function TLCLMemManager.NewItem: PLCLMemManagerItem;
|
|
begin
|
|
if FFirstFree<>nil then begin
|
|
// take from free list
|
|
Result:=FFirstFree;
|
|
FFirstFree:=FFirstFree^.Next;
|
|
Result^.Next:=nil;
|
|
dec(FFreeCount);
|
|
end else begin
|
|
// free list empty -> create new node
|
|
New(Result);
|
|
{$R-}
|
|
inc(FAllocatedCount);
|
|
{$IfDef RangeChecksOn}{$R+}{$Endif}
|
|
end;
|
|
inc(FCount);
|
|
end;
|
|
|
|
procedure TLCLMemManager.SetMaxFreeRatio(NewValue: integer);
|
|
begin
|
|
if NewValue<0 then NewValue:=0;
|
|
if NewValue=FMaxFreeRatio then exit;
|
|
FMaxFreeRatio:=NewValue;
|
|
end;
|
|
|
|
procedure TLCLMemManager.SetMinFree(NewValue: integer);
|
|
begin
|
|
if NewValue<0 then NewValue:=0;
|
|
if NewValue=FMinFree then exit;
|
|
FMinFree:=NewValue;
|
|
end;
|
|
|
|
procedure TLCLMemManager.FreeFirstItem;
|
|
var Item: PLCLMemManagerItem;
|
|
begin
|
|
Item:=FFirstFree;
|
|
FFirstFree:=FFirstFree^.Next;
|
|
Dispose(Item);
|
|
end;
|
|
|
|
{ TLCLNonFreeMemManager }
|
|
|
|
procedure TLCLNonFreeMemManager.Clear;
|
|
var
|
|
i: Integer;
|
|
p: Pointer;
|
|
begin
|
|
if FItems<>nil then begin
|
|
for i:=0 to FItems.Count-1 do begin
|
|
p:=FItems[i];
|
|
FreeMem(p);
|
|
end;
|
|
FItems.Free;
|
|
FItems:=nil;
|
|
end;
|
|
FCurItem:=nil;
|
|
FEndItem:=nil;
|
|
FCurSize:=FItemSize*4; // 4 items
|
|
end;
|
|
|
|
constructor TLCLNonFreeMemManager.Create(TheItemSize: integer);
|
|
begin
|
|
FItemSize:=TheItemSize;
|
|
FFirstSize:=FItemSize*4; // 4 items => the first item has 8 entries
|
|
FCurSize:=FFirstSize;
|
|
end;
|
|
|
|
destructor TLCLNonFreeMemManager.Destroy;
|
|
begin
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TLCLNonFreeMemManager.NewItem: Pointer;
|
|
begin
|
|
if (FCurItem=FEndItem) then begin
|
|
// each item has double the size of its predecessor
|
|
inc(FCurSize,FCurSize);
|
|
if (FMaxItemsPerChunk>0) and (FCurSize>FMaxItemsPerChunk*FItemSize) then
|
|
FCurSize:=FMaxItemsPerChunk*FItemSize;
|
|
GetMem(FCurItem,FCurSize);
|
|
if ClearOnCreate then
|
|
FillChar(FCurItem^,FCurSize,0);
|
|
if FItems=nil then FItems:=TFPList.Create;
|
|
FItems.Add(FCurItem);
|
|
FEndItem := FCurItem;
|
|
Inc(FEndItem, FCurSize);
|
|
end;
|
|
Result:=FCurItem;
|
|
Inc(FCurItem, FItemSize);
|
|
end;
|
|
|
|
procedure TLCLNonFreeMemManager.EnumerateItems(
|
|
const Method: TLCLEnumItemsMethod);
|
|
var
|
|
Cnt: Integer;
|
|
i: Integer;
|
|
p: Pointer;
|
|
Size: Integer;
|
|
Last: Pointer;
|
|
begin
|
|
if FItems<>nil then begin
|
|
Cnt:=FItems.Count;
|
|
Size:=FFirstSize;
|
|
for i:=0 to Cnt-1 do begin
|
|
// each item has double the size of its predecessor
|
|
inc(Size,Size);
|
|
p:=FItems[i];
|
|
Last := p;
|
|
Inc(Last, Size);
|
|
if i=Cnt-1 then
|
|
Last:=FEndItem;
|
|
while p<>Last do begin
|
|
Method(p);
|
|
Inc(p, FItemSize);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TExtMemoryStream }
|
|
|
|
function TExtMemoryStream.Realloc(var NewCapacity: PtrInt): Pointer;
|
|
begin
|
|
// if we are growing, grow at least a quarter
|
|
if (NewCapacity > Capacity) then
|
|
NewCapacity := Max(NewCapacity, Capacity + Capacity div 4);
|
|
Result := inherited Realloc(NewCapacity);
|
|
end;
|
|
|
|
end.
|
|
|