繁体   English   中英

C ++在变量的内存地址处做什么来“解除分配”它?

[英]What does C++ do at the memory address of a variable to “deallocate” it?

例如 。
当一个具有局部整数变量x的函数结束时,C ++对存储在与x对应的内存位置的值做了什么?
它是否插入随机值?

可能发生的事情 - 什么都没有。 删除某些东西需要资源,所以它只是调整指向该内存的堆栈指针。 这将导致下次使用此内存时覆盖它。

在不初始化变量的情况下使用变量时可以看到类似的东西。

int i;

i将在其中包含“垃圾”数据,这个“垃圾”来自内存中这个特定位置正在使用的时间。 可以是旧照片,文本文件或w / e。

这在很大程度上取决于实施。

在大多数情况下,什么也没做。 您解除分配(更改堆栈指针)。 在这种情况下,您不会修改内存。

在一些非常模糊的案例中,您可能会发现不同的事情。 在一个示例中,可以将RTOS RTEMS设置为在交易中写入存储器。 它可能会写一些特定的东西,如0xCDCDCDCD0xDEADBEEF 在调试这些RTOS系统中的内存问题时,这可能很有用,因为在使用坏内存时很容易识别。 但这种情况非常罕见

理论上这没有指定,但实际上没有对单个基本类型对象进行分配,如int,double,T *等。在某些情况下,堆栈指针不会被修改,编译器只是将空间重用于其他变量:

for (int i=0 ; i < 10 ; i++)
   foo(i);
for (int j=0 ; j < 10 ; j++)
   foo(j);

最有可能的是,编译器将重用i的空间来分配j 这可以通过gccgodbolt.org上轻松验证:

.L2:
        mov     edi, ebx
        add     ebx, 1
        call    foo(int)
        cmp     ebx, 10
        jne     .L2
        xor     ebx, ebx
.L3:
        mov     edi, ebx
        add     ebx, 1
        call    foo(int)
        cmp     ebx, 10
        jne     .L3

不仅循环相同,它们甚至不使用堆栈。 而不是堆栈, ij变量都在`ebx上分配。 在此示例中,分配和释放是完全透明的,并且是寄存器的简单使用或不使用。


更复杂的示例将在堆栈上执行相同的操作:

        xor     ebx, ebx ; <--- this is simply part of the next block
        sub     rsp, 48;   <--- allocating the stack space
.L2:
        mov     edi, ebx
        call    foo(int)
        mov     DWORD PTR [rsp+rbx*4], eax
        add     rbx, 1
        cmp     rbx, 10
        jne     .L2
        mov     rdi, rsp
        xor     ebx, ebx ; <--- this is simply part of the next block
        call    bar(int*)
.L3:
        mov     edi, ebx
        call    foo(int)
        mov     DWORD PTR [rsp+rbx*4], eax
        add     rbx, 1
        cmp     rbx, 10
        jne     .L3
        mov     rdi, rsp
        call    bar(int*)
        add     rsp, 48  ; <-- deallocating the stack space

另外,咨询第二个godbolt.org示例会产生:

        a[i] = foo(i);

在这里,两种情况的代码是相同的。 堆栈上没有解除分配或分配变量。 这条线:

        mov     DWORD PTR [rsp+rbx*4], eax

被翻译成

        mov     rdi, rsp
        call    bar(int*)

它只是相对于堆栈指针( rsp )写入数据。 它基本上找到的内容a根据相对于堆栈指针的位置。 堆栈指针不会在两个代码块之间更新,只能通过将堆栈指针复制到rdi来传递给bar()

  mov rdi, rsp call bar(int*) 


正如我所示,通常在一个区块的运行过程中,没有分配和解除分配。 通常,在函数的开头和结尾处,更新堆栈指针以反映变量。

与简单整数值不同,具有析构函数的类型更复杂,但我不会更深入地研究它,因为问题中没有提到它。

如果要创建对象并为其分配指针

Animal* animal =new Animal() ;

它将在内存中分配一个内存区域。就像你正在建造房屋并给某人发地址一样。

delete animal;

将去那个记忆区域并摧毁它。就像你用地址追踪房子并摧毁它。 然后它拥有的值将是垃圾。 作为一个好习惯,你必须使房子的地址为nullptr

animal = nullptr;

这种行为不是由C ++定义的,但我所知道的每个实现都是这样的。

编译器确定函数中局部变量需要多少字节。 编译器创建prolog代码,执行如下操作:

  SUB #NUMBEROFNEEDEDBYTES, SP

从堆栈中分配存储。

在内部,编译器为每个变量分配一些偏移量。 让我们说:

 X=12

然后

 12(SP) 

成为X的地址。

 ADD #4, 12(SP)

相当于

X += 4 ;

在函数结束时,编译器会创建一个类似于以下内容的epilog代码:

 ADD #NUMBEROFNEEDEDBYTES, SP

释放记忆。

然后,X具有在该位置发生在堆栈上的任何内容的初始值。 无论你放入什么X仍然是下一个功能。

与user3344003一样,变量x在堆栈上分配,即堆栈指针指向的位置。 如果你不知道堆栈指针是什么,你需要阅读它。 当函数结束时,对(所有)局部变量的引用将丢失,包括x。 现在,作为堆栈使用的内存被重用,因此包括x在内的所有局部变量的值都会丢失,因为它们的引用(堆栈上的内存地址)丢失,并且因为内存被重用于其他变量或目的。

即使在删除调用后,该对象也不会实际从内存中删除 这是一个漏洞,敏感信息可以通过转储文件泄露。 因此,最好用虚拟替换敏感对象并删除它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM