美文网首页
栈上的对象你以为是真的“自动释放”的吗

栈上的对象你以为是真的“自动释放”的吗

作者: xiaoliang1 | 来源:发表于2020-06-28 16:38 被阅读0次

每次都说栈上的对象是自动释放的。其实你很不明白为什么这么神奇,当你问时,别人还牛逼哄哄的说,哪有那么为什么,记住自动释放释放就行了。这无疑上学时“背课文”。问也不能问。还会遭到训斥,这是让人不能接受的时,你不能提出你的疑问。
今天就告诉你,其实很简单,就是出栈入栈导致的,分布在栈上的对象,在函数执行完毕。栈会恢复已经开辟的栈空间,所以你在反汇编时经常看到函数开头

sub         esp,0E8h

而在结尾时:

add         esp,0F4h  

(当然还有一些出栈,恢复上一个函数的参数等等一些环境)
这样这个函数执行完毕时,这个栈上的对象可能还在内存中,但当进行其他函数调用,或者其他操作时,这个对象的数据就会被覆盖掉。
所以,你就理算当然以为的“自动释放”,不用管理.
那你可能会说哪有这么简单,他会调用一些析构函数或者销毁函数。是自动释放时调用的。
其实不是这样的,因为调用这是编译器的做的,你看着表面没有调用析构函数或者销毁函数。这都是编译器帮你写了汇编。来通知你,释放前的通知,你可以做一些事,释放这个对象销毁前,要销毁的堆上数据。
C++这个语言都是站编译器的角度看问题的。底层没什么数据结构和很牛逼的设计来支持,所以只能静态语言了。只能靠编译器隐式帮你做一些操作。
下面用代码+汇编代码来看来:

void test3() {

    vector<int>p1;
    p1.push_back(1);

}

C++代码就这么简单,p1会在这个函数执行完时,调用vector<int,std::allocator<int> >::~vector<int,std::allocator<int> >这个析构函数,返回代码:

void test3() {
00CA8E60  push        ebp  
00CA8E61  mov         ebp,esp  
00CA8E63  push        0FFFFFFFFh  
00CA8E65  push        0CB196Dh  
00CA8E6A  mov         eax,dword ptr fs:[00000000h]  
00CA8E70  push        eax  
00CA8E71  sub         esp,0E8h  
00CA8E77  push        ebx  
00CA8E78  push        esi  
00CA8E79  push        edi  
00CA8E7A  lea         edi,[ebp-0F4h]  
00CA8E80  mov         ecx,3Ah  
00CA8E85  mov         eax,0CCCCCCCCh  
00CA8E8A  rep stos    dword ptr es:[edi]  
00CA8E8C  mov         eax,dword ptr [__security_cookie (0CB8008h)]  
00CA8E91  xor         eax,ebp  
00CA8E93  mov         dword ptr [ebp-10h],eax  
00CA8E96  push        eax  
00CA8E97  lea         eax,[ebp-0Ch]  
00CA8E9A  mov         dword ptr fs:[00000000h],eax  
00CA8EA0  mov         ecx,offset _5BA660AA_ConsoleApplication16@cpp (0CBA028h)  
00CA8EA5  call        @__CheckForDebuggerJustMyCode@4 (0CA14B5h)  

    vector<int>p1;
00CA8EAA  push        10h  
00CA8EAC  lea         ecx,[p1]  
00CA8EAF  call        std::vector<int,std::allocator<int> >::__autoclassinit2 (0CA12FDh)  
00CA8EB4  lea         ecx,[p1]  
00CA8EB7  call        std::vector<int,std::allocator<int> >::vector<int,std::allocator<int> > (0CA131Bh)  
00CA8EBC  mov         dword ptr [ebp-4],0  
    p1.push_back(1);
00CA8EC3  mov         dword ptr [ebp-0F0h],1  
    p1.push_back(1);
00CA8ECD  lea         eax,[ebp-0F0h]  
00CA8ED3  push        eax  
00CA8ED4  lea         ecx,[p1]  
00CA8ED7  call        std::vector<int,std::allocator<int> >::push_back (0CA17EEh)  

}
00CA8EDC  mov         dword ptr [ebp-4],0FFFFFFFFh  
00CA8EE3  lea         ecx,[p1]  
00CA8EE6  call        std::vector<int,std::allocator<int> >::~vector<int,std::allocator<int> > (0CA14C9h)  
00CA8EEB  push        edx  
00CA8EEC  mov         ecx,ebp  
00CA8EEE  push        eax  
00CA8EEF  lea         edx,ds:[0CA8F28h]  
00CA8EF5  call        @_RTC_CheckStackVars@8 (0CA1514h)  
00CA8EFA  pop         eax  
00CA8EFB  pop         edx  
00CA8EFC  mov         ecx,dword ptr [ebp-0Ch]  
00CA8EFF  mov         dword ptr fs:[0],ecx  
00CA8F06  pop         ecx  
00CA8F07  pop         edi  
00CA8F08  pop         esi  
00CA8F09  pop         ebx  
00CA8F0A  mov         ecx,dword ptr [ebp-10h]  
00CA8F0D  xor         ecx,ebp  
00CA8F0F  call        @__security_check_cookie@4 (0CA141Fh)  
00CA8F14  add         esp,0F4h  
00CA8F1A  cmp         ebp,esp  
00CA8F1C  call        __RTC_CheckEsp (0CA14CEh)  
00CA8F21  mov         esp,ebp  
00CA8F23  pop         ebp  
00CA8F24  ret  

}

很明显编译主动调用了std::vector<int,std::allocator<int> >::~vector<int,std::allocator<int> > (0CA14C9h) 这个析构函数
,如果成员变量指向了堆上的数据,请释放,并置NULL;
这只是冰山一角,好多都是编译器帮你做了什么。而且还是隐式的。
栈上的数据就如果在覆盖前,其实还是能拿到的、

Base test4() {

    Base p1;
    p1.a = 10;
    printf("0x%x", &p1);
    return p1;
}



int main()
{
    Base p1=  test4();
    return EXIT_SUCCESS;
}

你可以打断点查看main这个p1,即使调用析构函数.在覆盖前,你还是可以看到的,这个对象还在不子,就看覆盖没有覆盖。
这是帮助你理解自动释放。我自己的心得,之前也从未想过这个问题。可能你早已知道这些,但是我的心得。

相关文章

  • 栈上的对象你以为是真的“自动释放”的吗

    每次都说栈上的对象是自动释放的。其实你很不明白为什么这么神奇,当你问时,别人还牛逼哄哄的说,哪有那么为什么,记住自...

  • 【16】内存管理机制

    1. 内存:栈区间、堆区间 栈:栈上的内存是系统自动开辟,自动释放堆:堆上的内存需要手动开辟,手动释放。但在pyt...

  • 以“自动释放池块”降低内存峰值--Effective笔记

    1,自动释放池排布在栈中,对象收到autorelease消息后,系统将其放在最顶端的池里。 2,合理运用自动释放池...

  • iOS面试题:NSAutoreleasePool 是怎么工作的?

    原文:iOS面试题大全 自动释放池以栈的形式实现:当你创建一个新的自动释放池时,它将被添加到栈顶。当一个对象收到发...

  • autoreleasepool自动释放池(就问你点不点心了...

    送一波干货: 所谓自动释放池:自动释放池是用来存放对象的,存储在自动释放池中的对象,在自动释放次销毁的时候会给池子...

  • 2021UpdateC#.NET笔试题基础篇

    1.C#中堆和栈的区别? 栈:由编译器自动分配、释放。在函数体中定义的变量通常在栈上。堆:一般由程序员分配释放。用...

  • 自动释放池

    自动释放池 作用自动释放对象的所有 autorelease 的对象,在出了作用域之后,会被自动添加到最近创建的自动...

  • 自动释放池

    自动释放池 作用自动释放对象的所有 autorelease 的对象,在出了作用域之后,会被自动添加到最近创建的自动...

  • Js堆棧理解

    栈(stack) 自动分配的内存空间,它由系统自动释放; 堆(heap) 动态分配的内存,大小不定也不会自动释放。...

  • iOS-内存管理 堆栈

    为什么管理内存: 程序在运行的时候,要创建大量的对象,这些对象放在堆和栈上。(基本类型放在栈上,由系统自动管理。)...

网友评论

      本文标题:栈上的对象你以为是真的“自动释放”的吗

      本文链接:https://www.haomeiwen.com/subject/njjwfktx.html