当内存被释放时,Ada 会发生什么?

What happens in Ada when memory is deallocated?

我对 Ada 完全陌生,我必须学习它才能参加学校的课程。

我做过的其中一个练习要求一个过程来交换指针的地址,然后将指针的地址更改为另一个指针的地址,并释放之前的地址。

正如您在下一个示例中所看到的,我正在执行所需的操作,但我很想知道当该地址被释放时发生了什么,通过持有对它的引用,并意识到它会放入垃圾在其中,我猜测该地址的标志已更改,并且某些东西告诉编译器该内存地址已被释放,我只是不确定也无法在网上找到表明我的假设正确与否的东西。

procedure Main is
   type T_Pointer is access Integer;
   I, J, aux: T_Pointer;
   
   procedure FreeMemoryAddress is new Unchecked_Deallocation(integer, T_Pointer);
   
   procedure ChangePointerAddress(Origen: in out T_Pointer; destino: in T_Pointer);
   
   procedure ChangePointerAddress(Origen: in out T_Pointer; destino: in T_Pointer)
   is
   begin
      origen:=destino;
   end ChangePointerAddress;

   procedure SwapPointers (I, J: in out T_Pointer);

   procedure SwapPointers (I, J: in out T_Pointer)
   is
      aux: T_Pointer;
   begin
      aux := new Integer;
      Aux := I;
      I:=J;
      J:=Aux;

   end SwapPointers;


begin

   I:=new Integer;
   J:=new Integer;

   Put_Line("i's uninitialized value: " & integer'Image(I.all));


   Put_Line("i's address: " & System.Address_Image(I.all'Address));
   Put_Line("j's address: " & System.Address_Image(j.all'Address));


   SwapPointers(I, J);
   Put_Line("After swapping:");
   Put_Line("i's address: " & System.Address_Image(I.all'Address));
   Put_Line("j's address: " & System.Address_Image(j.all'Address));
   
   aux:=j;
   FreeMemoryAddress(j);
   Put_Line("aux's value: " & Integer'Image(aux.all)); --garbage
   Put_Line("aux's address: " & System.Address_Image(aux.all'Address));

end Main;

看到 I.all 的初始值为 0,我有点惊讶,因为编译器不需要确保分配的内存已初始化(至少,ARM 2012 4.8(9) says "any implicit initial value is assigned", see ARM 3.3.1(10), none 这里就是这种情况)。 VxWorks 5.3 的 GNAT 过去不初始化分配的数据,这让那些在 Windows 上开发的人转向 VxWorks 目标时感到惊讶;我们制作了我们自己的内存分配器版本 (s-memory.adb),它用 16#deadbeef#.

填充了内存

我们的分配器还使用类似但不同的模式填充已释放的内存(16#feebdaed#?-这是前一段时间)。

在 macOS 上,可能在这种情况下,GNAT 内存释放器调用 C free(),它会做任何它做的事情。返回的内存可能会作为 re-linking 的一部分被覆盖到系统内存区域,and/or 立即重新使用,例如通过您的 post-Free 代码。

概述了 Ada 中内存管理的一些方面 . In the particular case of Unchecked_Deallocation, the standard advises that an instance "should actually reclaim the storage." As @Simon Wright , the deallocation details may be implementation specific—marking, zeroing or poisoning freed memory—depending on the host operating system. MacOS, for example,使用了几种这样的 security-related 策略;你可能想研究一下你的 OS.

在下面的变体中,我添加了一个 Default_Value 方面和代码来显示 J 被释放前后的值。在调用后尝试引用 J.all 的值,以查看尝试取消引用 null.

引发的错误
Before Free (J):
J value: -1
J address: 000060000085C030
After Free (J):
J value:  756334640
J address: 000060000085C030

代码:

with Ada.Text_IO;                use Ada.Text_IO;
with Ada.Unchecked_Deallocation; use Ada;
with System.Address_Image;       use System;

procedure Main is
   type Int is new Integer with Default_Value => -1;
   type Int_Ptr is access Int;
   I, J, Temp : Int_Ptr;

   procedure Free is new Unchecked_Deallocation (Int, Int_Ptr);

   procedure SwapPointers (I, J : in out Int_Ptr) is
      Aux : Int_Ptr := new Int;
   begin
      Aux := I;
      I   := J;
      J   := Aux;
   end SwapPointers;

begin
   I := new Int;
   J := new Int;
   Put_Line ("I & J values: " & Int'Image (I.all) & " " & Int'Image (J.all));
   Put_Line ("I address: " & Address_Image (I.all'Address));
   Put_Line ("J address: " & Address_Image (J.all'Address));
   SwapPointers (I, J);
   Put_Line ("After swapping:");
   Put_Line ("I address: " & Address_Image (I.all'Address));
   Put_Line ("J address: " & Address_Image (J.all'Address));

   Put_Line ("Before Free (J):");
   Put_Line ("J value: " & Int'Image (J.all));
   Put_Line ("J address: " & Address_Image (J.all'Address));
   Temp := J;
   Free (J);
   Put_Line ("After Free (J):");
   Put_Line ("J value: " & Int'Image (Temp.all)); --garbage
   Put_Line ("J address: " & Address_Image (Temp.all'Address));
end Main;