Delphi越来越多自动释放的类型,到底是简单还是复杂了?

本文探讨了在从Delphi 7迁移至XE系列过程中遇到的动态数组管理问题。作者通过实例展示了动态数组的引用计数如何影响内存释放,揭示了自动释放可能导致的潜在错误,特别是在不同版本的Delphi中。文章强调了理解编译器规则的重要性,以避免因自动释放功能带来的不可预见的程序行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    这几天将D7下的一些组件转移到XE系列的编译环境中,根据网上别人写的总结文章进行改造,整个过程还算比较顺利,很快就可以编译通过并运行测试程序。但是随着测试工作的逐渐深入,一些以前没有注意到的问题慢慢浮上水面,并且花费了很长时间才最终找到问题的原因。

    其中一个困扰我很久的问题就是,动态数组是怎么解释的?回忆了一下,在Delphi7中,我们通常是使用SetLength来为一个动态数组分配内存,比如下面这个例子:

    type
      TTestData = array of Byte;
    function GetTestData(ASize: Integer): TTestData;
    begin
      SetLength(Result, ASize);
    end;

    当调用GetTestData后,我们就获得了一个大小为ASize的动态数组。我们可以将它保存到一个变量中,并且,可以对这个变量进行相应的操作:

    var
      FTestData: TTestData;       
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      FTestData := GetTestData(100);
      FTestData[50] := 10;
    end;

    那当不再需要使用时,我们需要如何释放这个数组呢?一般来说有两种做法,一种是直接将变量置为nil值,如:

  FTestData := nil;

   或者,是使用SetLength将数组长度设置为0   

  SetLength(FTestData, 0);
    这两种写法都可以实现将动态数组释放的功能。以前只知道使用,我一直没想过为什么这两句代码可以将动态数组释放掉的问题。不过一些基础的概念还是知道的,比如说知道动态数组的内存是由系统自动分配的,并且由系统自动回收,而这一功能得益于它的引用计数功能。我们上面调用 SetLength 实际上并不是一个内存分配函数,我们只是告诉 Delphi ,我们需要一个多大的数组, Delphi 自动帮我们申请内存并返回。当我们尝试改动一个动态数组长度的时候,我们来看下这个过程中 Delphi 会帮我们做什么,比如:
    FTestData := nil; //清空变量
    SetLength(FTestData, 50); //第一次设置数组长度,此时Delphi直接申请一个足够存放50长度的数组空间内存。
    SetLength(FTestData, 100);//第二次设置长度,这里需要扩展内存。如果当前内存空间充足,那么就直接在原址进行扩展。
        //如果当前地址段内存空间不足,那么,Delphi会重新申请另一个地址空间,然后将原来数组里的数据搬移过去,最后,
        //再将原来的内存释放掉。整个过程类似于内存重分配函数,ReallocMem

    这个是我所理解的动态数组的管理方法,不知道是否正确,但我想原理应该差不多。我唯一不清楚的是,Delphi如何管理数组的引用计数?引用计数是什么时候被改变的?就因为这个问题没搞清楚,导致我前段时间调试一个程序时一直找不到出现BUG原因在哪,一度纠结了两天时间。于是我决定这次一定要弄清楚,这个引用计数到底是如何管理的。

    我们先看一下动态数组在内存中的保存格式,该结构在D7XE下是一致的:

    引用计数         数组长度          数组内容

  &n

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值