delphi 内存管理与内存泄漏
delphi 内存管理与内存泄漏
基本数据类型/结构体/对象/数组 的 创建/拷贝/释放
-
unit1
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, StrUtils; type TForm1 = class(TForm) Memo1: TMemo; test3: TButton; test1: TButton; test2: TButton; test4: TButton; test5: TButton; test6: TButton; Edit1: TEdit; btn1: TButton; procedure test1Click(Sender: TObject); procedure test2Click(Sender: TObject); procedure test3Click(Sender: TObject); procedure test4Click(Sender: TObject); procedure test5Click(Sender: TObject); procedure test6Click(Sender: TObject); procedure Memo1DblClick(Sender: TObject); procedure btn1Click(Sender: TObject); private { Private declarations } public { Public declarations } procedure writeLog(s: string); end; var Form1: TForm1; implementation uses Unit2; {$R *.dfm} procedure TForm1.writeLog(s: string); begin Memo1.Lines.Add(s); end; procedure TForm1.test1Click(Sender: TObject); var Util: TUtil; begin //字符串与字符串数组 Util := TStrArrUtil.create; writeLog(Util.Show); writeLog(Util.toString); FreeAndNil(Util); end; procedure TForm1.test2Click(Sender: TObject); var Util: TUtil; begin //基本类型数组 Util := TByteArrUtil.create; writeLog(Util.Show); writeLog(Util.toString); FreeAndNil(Util); end; procedure TForm1.test3Click(Sender: TObject); var Util: TUtil; p: Pointer; begin //对象数组 Util := TObjArrUtil.create; p := @TObjArrUtil(Util).ObjArr[0]; writeLog(IntToStr(dword(p))); writeLog(Util.Show); writeLog(Util.toString); FreeAndNil(Util); writeLog(TNewObject(p^).objName); //必须重写destroy,否则内存泄漏 end; procedure TForm1.test4Click(Sender: TObject); var Util: TUtil; begin //结构体数组 基本类型 引用类型 Util := TRecArrUtil.create; writeLog(Util.Show); writeLog(Util.toString); // FreeAndNil(Util); Util.Free; end; procedure TForm1.test5Click(Sender: TObject); var objsrc, objDest: TNewObject; begin writeLog('TNewObject.create'); //对象拷贝assign 浅复制与深复制 objsrc := TNewObject.create('srcObj'); writeLog('subObj.create'); objsrc.subObj := TNewObject.create('subObj'); writeLog(objsrc.objName); writeLog(objsrc.subObj.objName); writeLog('objsrc.deepClone'); objDest := objsrc.deepClone; //深拷贝,生成新对象 writeLog(objDest.objName); writeLog(objDest.subObj.objName); objDest.objName := 'Test'; objDest.subObj.objName := 'subTest'; writeLog('---------------- objsrc'); writeLog(objsrc.objName); writeLog(objsrc.subObj.objName); writeLog('---------------- objDest'); writeLog(objDest.objName); writeLog(objDest.subObj.objName); FreeAndNil(objsrc); //必须重写destroy,否则内存泄漏 FreeAndNil(objDest); //必须重写destroy,否则内存泄漏 end; procedure TForm1.test6Click(Sender: TObject); var Util: TUtil; i, iMax: Integer; p: Pointer; begin //内存回收 iMax := StrToIntDef(Trim(Edit1.Text), 10); for i:= 1 to iMax do begin Util := TobjRecArrUtil.create; p := @TobjRecArrUtil(Util).objRecArr[0]; writeLog(IntToStr(dword(p))); writeLog(Util.Show + IntToStr(i)); writeLog(Util.toString); FreeAndNil(Util); //必须重写destroy,否则内存泄漏 end; writeLog(TobjRec(p^).objNew.objName); end; procedure TForm1.Memo1DblClick(Sender: TObject); begin Memo1.Lines.Clear; end; procedure TForm1.btn1Click(Sender: TObject); var //静态数组 结构体 定长,声明即自动分配内存,可以直接复制 recArr, recArr2: TRecArr; byteArr, byteArr2: TByteAarr; StrArr, StrArr2:TStrArr; ObjArr, ObjArr2: TObjArr; //动态数组 不定长, 只是指向同一内容要手动分配内存循环单独复制或者Copy bArr, bArr2: array of Byte; sArr, sArr2: array of string; sTemp: String; i: Integer; begin for i:= Low(byteArr) to High(byteArr) do begin byteArr[i] := i; end; //复制 byteArr2 := byteArr; //CopyMemory(@byteArr2, @byteArr, Length(byteArr)); for i:= Low(byteArr2) to High(byteArr2) do begin byteArr2[i] := i + 10; end; writeLog(TByteArrUtil.Show(byteArr)); writeLog(TByteArrUtil.Show(byteArr2)); for i:= Low(recArr) to High(recArr) do begin recArr[i].b := i; recArr[i].Bool := (i mod 2) = 1; recArr[i].int := ord(inttostr(i)[1]); end; //复制 recArr2 := recArr; //CopyMemory(@recArr2, @recArr, Length(byteArr)); for i:= Low(recArr2) to High(recArr2) do begin recArr2[i].b := i + 10; recArr2[i].Bool := (i mod 2) = 1; recArr2[i].int := i+ 20; end; writeLog(TRecArrUtil.Show(recArr)); writeLog(TRecArrUtil.Show(recArr2)); for i:= Low(StrArr) to High(StrArr) do begin StrArr[i] := 'src' + IntToStr(i); end; //复制 数组内字符串还会复制 //StrArr2 := StrArr; //CopyMemory(@StrArr2, @StrArr, Length(StrArr)); //内存错: 数组string无空间 for i:= Low(StrArr2) to High(StrArr2) do begin StrArr2[i] := 'dest' + IntToStr(i); end; writeLog(TStrArrUtil.Show(StrArr)); writeLog(TStrArrUtil.Show(StrArr2)); //数组会自动回收,字符串就是字符数组,也会自动回收 //setLength分批内存有个过程,循环中对一个数组反复setlength会oom //栈内存(局部变量、字符串、数组)等会自动回收 //堆内存(对象、getmem)需要手动回收,否则会有内存泄漏 //result不宜为array 或者 string,且不宜在循环中反复调用。因为内存分批与回收有过程 //假如机器性能低、回收不及时容易oom //基本类型数组和字符串复制可以直接复制, 也可以循环单个复制 //对象数组,只会复制数组内存,2个数组内指针地址相同,指向内容相同. 只能循环单个重新复制赋值 for i:= Low(ObjArr) to High(ObjArr) do begin ObjArr[i] := TNewObject.create(TNewObject.ClassName + IntToStr(i)); ObjArr[i].subObj := TNewObject.create('subObj' + IntToStr(i)); end; //复制 ObjArr2 := ObjArr; //CopyMemory(@StrArr2, @StrArr, Length(StrArr)); //内存错: 数组string无空间 for i:= Low(ObjArr2) to High(ObjArr2) do begin ObjArr2[i].objName := TNewObject.ClassName + IntToStr(i + 10); ObjArr2[i].subObj.objName := 'subObj' + IntToStr(i + 10); //ObjArr2[i] := TNewObject.create(TNewObject.ClassName + IntToStr(i + 10)); //ObjArr2[i].subObj := TNewObject.create('subObj' + IntToStr(i + 10)); end; writeLog(TObjArrUtil.Show(ObjArr)); writeLog(TObjArrUtil.Show(ObjArr2)); //动态数组 只是引用,不会在复制时分配新内存 SetLength(bArr, 10); for i:= Low(bArr) to High(bArr) do begin bArr[i] := i; end; //复制 不重新分配内存 //bArr2 := bArr; bArr2 := Copy(bArr); for i:= Low(bArr2) to High(bArr2) do begin bArr2[i] := i + 10; end; sTemp := ''; for i:= Low(bArr) to High(bArr) do begin sTemp := sTemp + inttostr(bArr[i]) + ' ' + #13#10; end; writeLog(sTemp); sTemp := ''; for i:= Low(bArr2) to High(bArr2) do begin sTemp := sTemp + inttostr(bArr2[i]) + ' ' + #13#10; end; writeLog(sTemp); SetLength(sArr, 10); for i:= Low(sArr) to High(sArr) do begin sArr[i] := 'src' + IntToStr(i); end; //sArr2 := sArr; //不重新分配内存 sArr2 := Copy(sArr); for i:= Low(sArr2) to High(sArr2) do begin sArr2[i] := 'dest' + IntToStr(i); end; sTemp := ''; for i:= Low(sArr) to High(sArr) do begin sTemp := sTemp + inttostr(i) + ': ' + sArr[i] + #13#10; end; writeLog(sTemp); sTemp := ''; for i:= Low(sArr2) to High(sArr2) do begin sTemp := sTemp + inttostr(i) + ': ' + sArr2[i] + #13#10; end; writeLog(sTemp); end; end.
-
unit2
unit Unit2;
interface
uses SysUtils;
const
I_Low = 0;
I_High = 9;
MB = 1024 * 1024;
MEM_SIZE = MB * 10;
type
TNewObject = class;
TBaseRec = record
b: Byte;
Bool: Boolean;
int: Integer;
end;
TarrRec = array [I_Low .. I_High] of TBaseRec;
TobjRec = record
s: string;
obj: TObject;
objNew: TNewObject;
end;
TRecArr = array [I_Low .. I_High] of TBaseRec;
TByteAarr = array[I_Low .. I_High] of Byte;
TStrArr = array[I_Low .. I_High] of string;
TObjArr = array[I_Low .. I_High] of TNewObject;
TobjRecArr = array [I_Low .. I_High] of TobjRec;
TNewObject = class
public
p: Pointer;
objName: string;
subObj: TNewObject; //free能释放干净么?有没有内存泄漏?
function deepClone(): TNewObject;
constructor create(sName: string = 'TNewObject');
destructor destroy(); override;
end;
TUtil = class
public
procedure Init(); virtual;
function toString(): string; virtual;
function Show(): string; virtual;
constructor create(); virtual;
end;
TRecArrUtil = class(TUtil)
private
fRecArr: TRecArr;
public
procedure Init(); override;
function toString(): string; override;
function Show(): string; overload; override;
class function Show(var RecArr: TRecArr): string; overload;
end;
TByteArrUtil = class(TUtil)
private
fByteAarr: TByteAarr;
public
procedure Init(); override;
function toString(): string; override;
function Show(): string; overload; override;
class function Show(var ByteAarr: TByteAarr): string; overload;
end;
TStrArrUtil = class(TUtil)
private
fStrArr: TStrArr;
public
procedure Init(); override;
function toString(): string; override;
function Show(): string; overload; override;
class function Show(var StrArr: TStrArr): string; overload;
end;
TObjArrUtil = class(TUtil)
private
fObjArr: TObjArr;
public
procedure Init(); override;
function toString(): string; override;
function Show(): string; overload; override;
class function Show(var ObjArr: TObjArr): string; overload;
destructor destroy(); override; //不加会内存泄漏
property ObjArr: TObjArr read fObjArr;
end;
TobjRecArrUtil = class(TUtil)
private
fobjRecArr: TobjRecArr;
public
procedure Init(); override;
function toString(): string; override;
function Show(): string; override;
destructor destroy(); override; //不加会内存泄漏
property objRecArr: TobjRecArr read fobjRecArr;
end;
implementation
{ TNewObject }
constructor TNewObject.create(sName: string = 'TNewObject');
begin
// GetMem(p, MEM_SIZE); // out of memory
objName := sName;
end;
function TNewObject.deepClone: TNewObject;
begin
Result := TNewObject.Create;
Result.objName := Self.objName;
if Assigned(subObj) then
Result.subObj := subObj.deepClone;
end;
destructor TNewObject.destroy;
begin
// FreeMem(p);
if Assigned(subObj) then subObj.Free;
end;
{ TUtil }
constructor TUtil.create;
begin
Init;
end;
procedure TUtil.Init;
begin
end;
function TUtil.Show: string;
begin
Result := Self.ClassName + '.show' + #13#10;
end;
function TUtil.toString: string;
begin
Result := Self.ClassName + '.toString' + #13#10;
end;
{ TRecArrUtil }
procedure TRecArrUtil.Init;
var
i: Integer;
begin
for i:= Low(fRecArr) to High(fRecArr) do
begin
fRecArr[i].b := i;
fRecArr[i].Bool := (i mod 2) = 1;
fRecArr[i].int := ord(inttostr(i)[1]);
end;
end;
function TRecArrUtil.Show: string;
var
i: Integer;
begin
for i:= Low(fRecArr) to High(fRecArr) do
begin
Result := Result + inttostr(i) + ': ' + inttostr(fRecArr[i].b) + ' ' + BoolToStr(fRecArr[i].Bool) + ' ' + inttostr(fRecArr[i].int) + #13#10;
end;
end;
class function TRecArrUtil.Show(var RecArr: TRecArr): string;
var
i: Integer;
begin
for i:= Low(RecArr) to High(RecArr) do
begin
Result := Result + inttostr(RecArr[i].b) + ' ' + booltostr(RecArr[i].Bool) + ' ' + inttostr(RecArr[i].int) + #13#10;
end;
end;
function TRecArrUtil.toString: string;
begin
Result := Show(fRecArr);
end;
{ TObjArrUtil }
destructor TObjArrUtil.destroy;
var
i: Integer;
begin
for i:= Low(fObjArr) to High(fObjArr) do
begin
fObjArr[i].Free;
end;
inherited;
end;
procedure TObjArrUtil.Init;
var
i: Integer;
begin
for i:= Low(fObjArr) to High(fObjArr) do
begin
fObjArr[i] := TNewObject.create(TNewObject.ClassName + IntToStr(i));
fObjArr[i].subObj := TNewObject.create('subObj' + IntToStr(i));
end;
end;
function TObjArrUtil.Show: string;
begin
Show(fObjArr);
end;
class function TObjArrUtil.Show(var ObjArr: TObjArr): string;
var
i: Integer;
begin
for i:= Low(ObjArr) to High(ObjArr) do
begin
Result := Result + inttostr(i) + ': ' + ObjArr[i].objName + ' ';
if Assigned(ObjArr[i].subObj) then
Result := Result + ObjArr[i].subObj.objName;
Result := Result + #13#10;
end;
end;
function TObjArrUtil.toString: string;
var
i: Integer;
begin
for i:= Low(fObjArr) to High(fObjArr) do
begin
Result := Result + inttostr(i) + ': ' + fObjArr[i].objName + ' ';
if Assigned(fObjArr[i].subObj) then
Result := Result + fObjArr[i].subObj.objName + #13#10;
end;
end;
{ TobjRecArrUtil }
destructor TobjRecArrUtil.destroy;
var
i: Integer;
begin
for i:= Low(fobjRecArr) to High(fobjRecArr) do
begin
if Assigned(fobjRecArr[i].objNew) then
fobjRecArr[i].objNew.Free;
if Assigned(fobjRecArr[i].obj) then
fobjRecArr[i].obj.Free;
end;
inherited;
end;
procedure TobjRecArrUtil.Init;
var
i: Integer;
begin
for i:= Low(fobjRecArr) to High(fobjRecArr) do
begin
fobjRecArr[i].s := IntToStr(i);
fobjRecArr[i].obj := TObject.Create;
fobjRecArr[i].objNew := TNewObject.create(TNewObject.ClassName + IntToStr(i));
fobjRecArr[i].objNew.subObj := TNewObject.create('subObj' + IntToStr(i));
end;
end;
function TobjRecArrUtil.Show: string;
var
i: Integer;
begin
for i:= Low(fobjRecArr) to High(fobjRecArr) do
begin
Result := Result + inttostr(i) + ': ' + fobjRecArr[i].s + ' ' + fobjRecArr[i].obj.ClassName + ' ' + fobjRecArr[i].objNew.objName + ' ';
if Assigned(fobjRecArr[i].objNew.subObj) then
Result := Result + fobjRecArr[i].objNew.subObj.objName;
Result := Result + #13#10;
end;
end;
function TobjRecArrUtil.toString: string;
var
i: Integer;
begin
for i:= Low(fobjRecArr) to High(fobjRecArr) do
begin
Result := Result + inttostr(i) + ': ' + fobjRecArr[i].s + ' ' + fobjRecArr[i].obj.ClassName + ' ' + fobjRecArr[i].objNew.objName + ' ';
if Assigned(fobjRecArr[i].objNew.subObj) then
Result := Result + fobjRecArr[i].objNew.subObj.objName;
Result := Result + #13#10;
end;
end;
{ TByteArrUtil }
procedure TByteArrUtil.Init;
var
i: Integer;
begin
for i:= Low(fByteAarr) to High(fByteAarr) do
begin
fByteAarr[i] := i;
end;
end;
function TByteArrUtil.Show: string;
begin
Result := Show(fByteAarr);
end;
class function TByteArrUtil.Show(var ByteAarr: TByteAarr): string;
var
i: Integer;
begin
for i:= Low(ByteAarr) to High(ByteAarr) do
begin
Result := Result + inttostr(ByteAarr[i]) + ' ' + #13#10;
end;
end;
function TByteArrUtil.toString: string;
var
i: Integer;
begin
for i:= Low(fByteAarr) to High(fByteAarr) do
begin
Result := Result + inttostr(i) + ': ' + inttostr(fByteAarr[i]) + ' ' ;
end;
end;
{ TStrArrUtil }
procedure TStrArrUtil.Init;
var
i: Integer;
begin
for i:= Low(fStrArr) to High(fStrArr) do
begin
fStrArr[i] := 'str' + inttostr(i);
end;
end;
function TStrArrUtil.Show: string;
begin
Result := Show(fStrArr);
end;
class function TStrArrUtil.Show(var StrArr: TStrArr): string;
var
i: Integer;
begin
for i:= Low(StrArr) to High(StrArr) do
begin
Result := Result + inttostr(i) + ': ' + StrArr[i] + #13#10;
end;
end;
function TStrArrUtil.toString: string;
var
i: Integer;
begin
for i:= Low(fStrArr) to High(fStrArr) do
begin
Result := Result + fStrArr[i] + ' ' + #13#10;
end;
end;
end.
- 运行结果