delphi D11编程语言手册 学习笔记(P393-419) 对象与内存

 

 这本书可以在 Delphi研习社②群 256456744 的群文件里找到. 书名: Delphi 11 Alexandria Edition.pdf

置顶: 一看到"内存"这两个字我就发抖....

 这些年来,Delphi 行动装置编译器提供了一个不同的内存模式,称为自动参考计数(ARCAutomatic Reference Counting)。这个管理模式是由 Apple开始从 Objective-C 语言推广的,ARC 让编译器支持对象参考在内存中被使用的次数,并在这个次数被设为 0 的时候(也就是该对象没有在任何地方被使用到的时候),就把该对象自动释放掉。这个作法跟 Delphi 在所有平台上对接口参考所处理的作法很像。Delphi 10.4 开始,对 ARC 的支持已经从所有平台全数取消了。

 

 全局数据、堆栈以及 Heap
  在任何一个 Object Pascal 的应用程序里面所使用的内存可以分成两个领域:源码与数据.在一个程序的执行文件里面包含几个部分,包含资源(例如图片、窗体描述档案),以及由程序加载到内存使用的函式库。这些内存区块是只读的(在几个平台上,例如 Windows),且可以让多个处理程序共享.仔细研究资料部分也是很有趣的。Object Pascal 程序(像大多其他的编程语言的写法一样)的数据是分成三大块来储存的:全局内存、堆栈、Heap

1.全局内存

  也叫静态内存,用来储存生命周期从应用程序开始到结束为止的变量数据所需要的空间.这些空间不会被转移也不会被释放,直接到程序退出时,才会被释放.

全局变量就是使用这一类的内存.如果全局变量是一个类类型或是字符串/动态数组类型,使用到的全局内存空间只有4byte或者8byte的对象参考而已

2.堆栈  heap(堆)与 stack(栈)  

堆栈是动态的内存区域,这个区域会依照后进先出的顺序来配置与释放。这意味着最后被配置的内存对象必须最先被删除掉 .做个比喻:就是像弹匣一样,最后压入的子弹会被最先打出去!

堆栈内存一般是不会自动进行初始化也不会被自动清除的.这也是为什么局部变量一定要先初始化再使用的原因.

堆栈的大小通常是在编译作业的过程就已经决定了的.

程序需要的内存空间分为 heap(堆) 和 stack(栈);

heap(堆) 是自由存储区, 需要手动申请、手动释放 (手动挡).如果只申请,不释放, 就会发生"内存泄露";

stack(栈) 是自动存储区,自动申请、自动释放(自动挡).

不需要申请和释放空间的元素, 譬如变量(var)、结构(record)等, 是存与 stack(栈);
反之如需要 Create 和 Free 的对象、需要 GetMem 和 FreeMem 的指针等, 则是存于 heap(堆);

时间上,stack(栈) 比 heap(堆)  快一点点.

3.对象参考模型  

var
    NewButton,Button2: TButton;
begin
    NewButton:= TButton.Create(self);
    Button2 := Button1;

  Button1与Button2指向了相同的内存空间(地址),而NewButton则新申请了一个内存空间

当我们把对象当成参数传递给过程或者函数时,尽管没有使用var声明参数,但它仍然会把对象的内存地址给传递了进去:

procedure ChangeCaption (AButton: TButton; Text: string);
begin
    AButton.Text := Text;
end;
// Call...
ChangeCaption (Button1, ‘Hello’)

内存管理技巧:

  1.有Create就要有free. 当Create的参数Aowner不为nil时,表示此对象把释放流程,委托给Aowner进行处理,开发者可以不用再处理它的内存释放问题.当然,你也可以提前把对象释放掉而不会有任何问题.

procedure TForm1.FormClick(Sender: TObject);
var
  NewBtn1, NewBtn2, NewBtn3: TscGPCharImage;
begin
  NewBtn1 := TscGPCharImage.Create(Application); //所属当前程序 ,当程序退出时自动free
  NewBtn2 := TscGPCharImage.Create(Self);  //所属self指向当前窗体,当窗体关闭时自动free
  NewBtn3 := TscGPCharImage.Create(nil); //无主阿飘,自由类,不受管控,需要手动释放,否则容易造成内存泄漏
  //等价于下面一句,区别是一个有参数,一个无参数
   // NewBtn3 := TscGPCharImage.Create
   //do something
  NewBtn3.Free ;//使用完后,需要手动释放
end;

  2.对象只能释放一次.free方法会检查对象是否为nil,然后才会调用destroy虚拟解析函数.如果直接使用destroy,而不去判断对象是否存在,会导致内存报错.以下是free方法的原码:

procedure TObject.Free;
begin
  if Self <> nil then  //等价于: if Assigned(self) then...
  Destroy;
end;

  3.关于内存释放的问题

    FreeAndNil 干脆利落,直接清空对象指针与释放内存空间. 局部变量释放资源时,可以考虑用FreeAndNil()释放资源,这样效率会高些,能提高内存的利用率。   

    Free不清除指针,也不清除内存,它只是把内存标记为可回收资源,并委托给系统自动处理.同时它没有将对象指针值置为Nil.打个比方,这个盒子里的东西我不想要了,我给它贴了张标签,说它是可丢弃的.然而我又没有马上倒掉它.而是等到了我需要用它来装东西的时候,我再把它倒掉,用来装新东西.,所以当我们Free对象之后,再用 obj=nil去判断一个对象是否为nil时,其实是不一定等于的!因为东西可能还在那里

    

    nil会直接清除(初始化)指针,使指针不指向该对象的地址,也不指向任何内存地址.

    DisPosOf调用的是Free,主要用在移动端,当然桌面程序里面也可以使用.

    Release 等待资源不再使用后释放资源,同样不修改Obj指针为Nil,所以在OnDestroy中最好使用Release进行资源释放操作。

     单纯通过Assigned(Obj)判断对象是否已经创建是不够的,因为如果对象通过Free/Release进行资源释放的话,Obj指向的是一个未知地址, 而非Nil,所以需要用(Not Assigned(Obj)) And (Not (Obj is  TObject)) 来判断该对象是否已经创建在内存中。

 

抱歉兄弟们,从402页到422页,我真的看不懂了...本小节到此结束...

posted @ 2022-12-10 19:59  一曲轻扬  阅读(211)  评论(0编辑  收藏  举报