结构体类似如下:RRecord = record
    EndTime   :TDateTime;   
    StartTime :TDateTime;
    i1 :integer;
    i2 :integer;
    i3 :integer;
    i4 :integer;
    i5 :integer;
    i6 :integer;
    s1     :string;
    s2     :string;
    s3     :string;
end;假设情况如下:
某时刻程序动态申请内存空间 “GetMem(p, sizeof(RRecord)); ” 。
然后程序有这样的赋值操作 :
p.s1 := ......; p.s2 := ......; p.s3 := ......;
代码跑了一段时间,释放申请的内存空间,程序这样做 :
FreeMem(p, sizeof(RRecord)); 请问 FreeMem 时 ,原本里面的s1,s2,s3会自己自动释放么??还是说到程序退出时才自动释放??
需要自己手动释放么??如何释放??

解决方案 »

  1.   

    GetMem(p, sizeof(RRecord))//申请了s1,s2,s3所需的内存空间。
    FreeMem(p, sizeof(RRecord));//释放了s1,s2,s3所需的内存空间。所以是不用的。
      

  2.   

    s1,s2,s3 不是只是指针么?会不会 s1,s2,s3 是被释放掉了,但是 s1,s2,s3指向的内容依旧还在??
      

  3.   

    1楼误导了.GetMem和FreeMem就需要事先把字符串 := ''
    如果是用
    New和Dispose则不用
      

  4.   

    你可以试验一下不就明白了  GetMem(p, sizeof(RRecord));
      SetLength(P.s1 , 10 * 1024*1024);
      PByte(P.s1)^ := 0;
      ShowMessage('看看程序使用的内存,应该>10M');
      FreeMem(P); 
      ShowMessage('现在看看程序使用的内存,应该还是>10M');
      
      然后换成这样
      New(p);
      SetLength(P.s1 , 10 * 1024*1024);
      PByte(P.s1)^ := 0;
      ShowMessage('看看程序使用的内存,应该>10M');
      Dispose(P); 
      ShowMessage('现在看看程序使用的内存,应该明显减少了10M');或者这样
       GetMem(p, sizeof(RRecord));
      SetLength(P.s1 , 10 * 1024*1024);
      PByte(P.s1)^ := 0;
      ShowMessage('看看程序使用的内存,应该>10M');
      P.s1 := '';     //把字符串释放掉
      FreeMem(P); 
      ShowMessage('现在看看程序使用的内存,应该明显减少了10M');
      

  5.   

    我这里测试结果是,需要手动释放,赋值空字符串就行。
    type
      R = record
        I: Integer;
        S: string;
      end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      ShowMessage(string(Tag));
    end;procedure TForm1.FormCreate(Sender: TObject);
    var
      P: ^R;
    begin
      GetMem(P, SizeOf(R));
      P^.I := 1;
      P^.S := 'abc';
      Tag := Integer(P^.S);
      ShowMessage(P^.S);
      //P^.S := '';//如果这里没有手动释放,则点击Button1时,还是会显示abc。从调试状态下的汇编代码中也不会看到用来释放字符串的LStrClr。
      FreeMem(P, SizeOf(R));
    end;
      

  6.   

    可以不用手动释放。由delphi管理的.
      

  7.   

    貌似关键是用Dispose来释放。貌似用GetMem和Dispose的组合也可以——New内部调用了GetMem, 然后调用System.Initialize,就是把字符串、接口什么的清零。
      

  8.   

    s11ss很认真在研究.
    你的方法测试不完全对,不能拿字符串常量来测试这个
    给你看个例子:var
      D : integer;procedure TestProc1;
    var
      S : AnsiString;
    begin
      S := 'abcdefghijklmn';   //这里并未复制一个,而是给常量字符串的引用+1
      D := Integer(S);
      S := '';           //引用-1,并未释放 abcd...占的内存,实际上释放不了,它在只读内存区,靠
    end;procedure TestProc2;
    var
      S : AnsiString;
    begin
      SetLength(S , 20);  //生成一个全新的字符串,一定是全新的从堆上分配的.
      S := 'abc' + S;
      D := Integer(S);
      S := ''; //这里就真正释放了,所以后面调用D要出错.
    end;procedure TForm1.Button1Click(Sender: TObject);
    begin
      TestProc1;
      ShowMessage(AnsiString(D));  //这个不出错,但是显示的是 abcdefghijklmn
      TestProc2;
      ShowMessage(AnsiString(D));  //这个就要出错了.
    end;这虽然不是Delphi本身的问题,但是Delphi确实存在常量字符串的问题,而且从出生到现在一直有包括Delphi2010
    XE/XE2没作测试
      

  9.   

    4楼这样测试不准确 
    string 自动释放要 时机 
    在一个函数内用到 那么在这个函数内是不会自动释放的 
    完成这个函数后 才会检测释放
      

  10.   

    GetMem和Dispose也可以,一般不这么配对,习惯上是GetMem/FreeMem,New/Dispose
    程序本着谁申请谁释放的原则,如果用GetMem,回过头来看代码的时候,一定要找FreeMem.容易忽略Dispose
      

  11.   


    我当时就看调试状态的汇编代码了,我的那段代码会调用LStrAsg,跟进去会发现NewAnsiString,继续跟进去会执行到GetMem,证明确实生成字符串了——所以这儿的字符串常量用来测试没问题!
      

  12.   

    我的环境是Delphi2007,测试那个TestProc1也是会生成新的字符串,并且在S:=''的时候调用了LStrClr。
    不知道Delphi7是不是也是这样。
      

  13.   

    纠错虽然调用了LStrAsg,但是并没有执行到NewAnsiString,所以没生成新的字符串
      

  14.   

    procedure TestProc1;
    var
      S : AnsiString;
    begin
      S := 'abcdefghijklmn';
      PByte(S)^ := 0;   //出错,证明未复制新串,D7,D2010是这样,2007未测试,下班了,
      

  15.   

    To 9L:
    既然在只读内存区,那为什么引用计数可以修改?在S := 'abcdefghijklmn'之后,引用计数变成了0,之前是-1.
      

  16.   

    Sorry,那里没有对引用记数操作,常量字符串的记数为$FFFFFFFF
    procedure _LStrClr(var S);
              MOV     ECX,[EDX-skew].StrRec.refCnt    { fetch refCnt                  }
            DEC     ECX                             { if < 0: literal str           }
            JL      @@done      //常量字符串到这里就跳转了
              ......
    @@done:
      

  17.   

    是说我么? 好吧 我承认 我没有测试
    但是呢 你这样测试 不够准确 这个观点我还是坚持,至于你测出的结果与事实对于不对,我就不知了,我承认没深入了解 
    s11ss 的测试 在另一个button 事件里 显示信息 从语义上来说 比较准确
    语义准确了 并不代表测试的结果也会正确!
    你只要了解为什么出现 FreeAndNil 这个函数,大概就知道为什么了对于引用计数的机制 
    我的理解是:系统在某个时刻,进行全局扫描,打引用计数为0的内在释放 
    那是在什么时刻比较好呢 ?据说是处理完本次事件的下一次事件开始 
    关于string 类型 找到一篇文章 
    共同学习下
    http://www.cnblogs.com/zhengjuzhuan/archive/2010/03/15/1686257.html
      

  18.   

    typet1 = record
      f1:string;
      f2: variant;
      f3: IInterface
    end;...
    var
      p:^t1;
    begin
      new(p); //这句等价于 Getmem(p,sizeof(t1)); Initialize(p^);
      dispose(p); //这句等价于 Finalize(p^),FreeMem(p,sizeof(t1));
    ...对于string,variant,inteface这三种“号称”内存自管理的变量类型,Getmem和FreeMem太低阶了,不会顾及他的一些引用计数。
     
      

  19.   

    短字符串才会自动释放: s:string[x]; //1<x<255
      

  20.   

    http://www.cnblogs.com/zhengjuzhuan/archive/2010/03/15/1686257.html
    里 说得很清楚 推荐这文章 
    反正 结果就是 FreeMem 要手功释放  Dispose不用