内存的分配VS回收&构造函数VS析构函数
之前有一个问题一直困扰着我,就是一个变量出了作用域,我以为这个变量的内存就被回收了,其实不是这样的,昨天问了一个高手,才豁然开朗,自己在看相关代码的反汇编代码,才知道原来真是这样就。这个问题,我想简单的说一下内存的分配VS回收&构造函数VS析构函数之间的关系。
我的疑问:为什么p出了作用域,指向p的ptr还能读到p中arr的内容,难道p出了作用域,还没有析构?
下面的内容会解答这个疑问,先说说跟这篇文章有关的内容。
可能是因为平时习惯的原因,我们在实例化一个对象的时候,往往是一条语句实现两个功能:1分配内存;2调用构造函数
class A
{
public:
A()
{
i=;
j=;
} ~A(){}
int i;
int j;
}; A a1;
A * a2=new A();
这两中方式都是一步实现两个操作,分配内存和调用构造函数,如果A没写构造函数,即没有构造函数(编译器也不会自动生成),当然就不需要调用构造函数。
其实这两步是可以分开的,A a1;这句分开不了这两步,但A * a2=new A();是可以分开,同等的代码如下:
void* memory=operator new(sizeof(A));//分配内存
A* a2=new(memory) A();//在memory上调用A的构造函数
回收的时候,我们可以这样写:
delete a2;//这句等同下面两句
//a2->~A();
//operator delete(memory);
如果A没有析构函数,当然delete时也不会调用,原因请看我的博客:构造函数产生的点及原因。
也就是说A* a=new A();delete a;这两条语句,执行了四个操作:
分配内存->调用构造函数->调用析构函数->回收内存;
更多关于这四步分开的代码:
而我今天要说的是,这四步是完全可以分开的。既然这四步是可以分开的,那么解答上面那个疑问就很简单了。
Char* ptr;
{
Point p;
ptr=p;
}
P出了作用域,为什么ptr还能读到他的内容,原因很简单:因为上面几行代码只执行了前面三步,最后一步回收内存,还没有执行。出了作用域,就会执行析构,没说要回收内存,栈的内存要在方法返回之前才回收,也就是说一个方法如果大量的分配内存是很容易爆栈,即是你让栈中的变量出了作用域也没用,请不要搞混了。栈内存在方法返回的时候才回收,这一点就是爆栈的最重要原因,为什么不是在变量出作用域的时候,调用完析构函数,就回收内存呢?我也不知道为什么?,看方法test11的反汇编代码,的确是在方法返回的时候才回收内存?
那个疑问的源码如下:
#include "stdafx.h"
#include <iostream>
using namespace std; struct Point
{
char arr[];
Point()
{
for(int i=;i<;i++)
{
arr[i]='a';
}
arr[]='\0';
}
~Point(){}
operator char*()
{
return arr;
}
}; void test11()
{
char* ptr;
{
Point p;
ptr=p;
}
cout<<ptr<<endl;
} int _tmain(int argc, _TCHAR* argv[])
{
{
test11();
}
system("pause");
return ;
}
test11的反汇编代码如下:
void test11()
{
010431F0 push ebp //ebp表示栈顶指针
010431F1 mov ebp,esp //esp表示栈当前指针
009C31F3 push 0FFFFFFFFh
009C31F5 push offset __ehhandler$?test11@@YAXXZ (9CA3C8h)
009C31FA mov eax,dword ptr fs:[00000000h]
009C3200 push eax
009C3201 sub esp,0E4h
009C3207 push ebx
009C3208 push esi
009C3209 push edi
009C320A lea edi,[ebp-0F0h]
B::`scalar deleting destructor':
009C3210 mov ecx,39h
009C3215 mov eax,0CCCCCCCCh
009C321A rep stos dword ptr es:[edi]
009C321C mov eax,dword ptr [___security_cookie (9CF070h)]
009C3221 xor eax,ebp
009C3223 mov dword ptr [ebp-10h],eax
009C3226 push eax
009C3227 lea eax,[ebp-0Ch]
009C322A mov dword ptr fs:[00000000h],eax
char* ptr;
{
Point p;
009C3230 lea ecx,[p]
009C3233 call Point::Point (9C1541h)
009C3238 mov dword ptr [ebp-],
ptr=p;
009C323F lea ecx,[p]
009C3242 call A::~A (9C1546h)
009C3247 mov dword ptr [ebp-18h],eax
}
009C324A mov dword ptr [ebp-],0FFFFFFFFh
009C3251 lea ecx,[p]
009C3254 call A::`scalar deleting destructor' (9C154Bh)
cout<<ptr<<endl;
009C3259 mov esi,esp
009C325B mov eax,dword ptr [__imp_std::endl (9D039Ch)]
009C3260 push eax
009C3261 mov ecx,dword ptr [ebp-18h]
009C3264 push ecx
009C3265 mov edx,dword ptr [__imp_std::cout (9D03A0h)]
009C326B push edx
009C326C call std::operator<<<std::char_traits<char> > (9C132Fh)
009C3271 add esp,
009C3274 mov ecx,eax
009C3276 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (9D0390h)]
009C327C cmp esi,esp
009C327E call @ILT+(__RTC_CheckEsp) (9C13C5h)
}
009C3283 push edx
009C3284 mov ecx,ebp
009C3286 push eax
009C3287 lea edx,[ (9C32C0h)]
009C328D call @ILT+(@_RTC_CheckStackVars@) (9C1163h)
009C3292 pop eax //pop开始出栈 注意;这里才开始回收内存
09C3293 pop edx
009C3294 mov ecx,dword ptr [ebp-0Ch]
009C3297 mov dword ptr fs:[],ecx
009C329E pop ecx
009C329F pop edi
009C32A0 pop esi
009C32A1 pop ebx
009C32A2 mov ecx,dword ptr [ebp-10h]
009C32A5 xor ecx,ebp
009C32A7 call @ILT+(@__security_check_cookie@) (9C1046h)
009C32AC add esp,0F0h
009C32B2 cmp ebp,esp
009C32B4 call @ILT+(__RTC_CheckEsp) (9C13C5h)
009C32B9 mov esp,ebp //栈顶指针和栈当前指针指向同一个地址,即栈的长度就是一个指针的长度
009C32BB pop ebp //栈顶指针弹出,现在栈空了
009C32BC ret
我有这个疑问的原因就是:我以为在出作用域的时候不仅调用析构函数,还要回收内存,其实只是调用析构函数,内存在方法返回的时候才回收。
内存的分配VS回收&构造函数VS析构函数的更多相关文章
- JVM内存分配和回收
本文内容来自<Java编程思想(第四版)>第二章<一切都是对象>和第五章<初始化与清理>.作为一个使用了好几年的Javaer,再次看编程思想的前面章节(不要问我为什 ...
- 浅谈java内存分配和回收策略
一.导论 java技术体系中所提到的内存自动化管理归根结底就是内存的分配与回收两个问题,之前已经和大家谈过java回收的相关知识,今天来和大家聊聊java对象的在内存中的分配.通俗的讲,对象的内存分配 ...
- 深入理解JVM(4)——对象内存的分配策略
一.Java所承担的自动内存管理主要是针对对象内存的分配和回收. 二.在Java虚拟机的五块内存空间中,程序计数器.Java虚拟机栈.本地方法栈内存的分配和回收都具有确定性,一般在编译阶段就能确定需要 ...
- JVM运行内存分配和回收
本文来自网易云社区 作者:吕宗胜 Java语言与C语言相比,最大的特点是编程人员无需过多的关心Java的内存分配和回收,因为所有这一切,Java的虚拟机都帮我们实现了.JVM的内存管理,大大降低了开发 ...
- 【Java_基础】JVM内存模型与垃圾回收机制
1. JVM内存模型 Java虚拟机在程序执行过程会把jvm的内存分为若干个不同的数据区域来管理,这些区域有自己的用途,以及创建和销毁时间. JVM内存模型如下图所示 1.1 程序计数器 程序计数器( ...
- 【深入理解Java虚拟机】自动内存管理机制——垃圾回收机制
Java与C++之间有一堵有内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来.C/C++程序员既拥有每一个对象的所有权,同时也担负着每一个对象生 ...
- JVM内存结构与垃圾回收总结
1.JVM内存模型 JVM只不过是运行在你系统上的另一个进程而已,这一切的魔法始于一个java命令.正如任何一个操作系统进程那样,JVM也需要内存来完成它的运行时操作.记住:JVM本身是硬件的一层软件 ...
- 看完这篇文章,我奶奶都知道什么是JVM中的内存模型与垃圾回收!
扩展阅读:JVM从入门开始深入每一个底层细节 六.内存模型 6.1.内存模型与运行时数据区 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同数据区域. Java内存模型的主要目 ...
- JVM 内存模型及垃圾回收
java内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 程序计数器:程序计数器是指CPU中的寄存器,它保存的是程序当前执行的指令的地址(也可以说 ...
随机推荐
- 张小龙《微信背后的产品观》之PPT完整文字版
微信回顾 433天,一亿用户 成为移动互联网的新入口 启动(2010年11月19日) 用户数突破1亿 1.0 1月26日 2.0 5月10日 语音对讲 2.5 8月3日 查看那附近的人 3.0 10月 ...
- bzoj 3389
题意:给定1维连续T<= 1000000个点,以及n<=10000个线段,求最少的线段覆盖该区间.. 思路:很显然,贪心是可以做的..不过这一题最有意思的是使可以转换为最短路模型.. 如果 ...
- HDU 2019 数列有序!
Time Limit: 1000 MS Memory Limit: 32768 KB 64-bit integer IO format: %I64d , %I64u Java class name ...
- 开源IP代理池续——整体重构
开源IP代理池 继上一篇开源项目IPProxys的使用之后,大家在github,我的公众号和博客上提出了很多建议.经过两周时间的努力,基本完成了开源IP代理池IPProxyPool的重构任务,业余时间 ...
- 20 个免费的 Bootstrap 的后台管理模板
之前 OSC 曾经发过多个后台管理界面模板的推荐,例如: 50 个漂亮的后台管理界面模板 25 个精美的后台管理界面模板和布局 分享 6 套超酷的后台管理员界面网站模板 30个优秀的后台管理界面设计案 ...
- C#函数式编程之由函数构建函数
在面向对象的编程中,如果我们需要复用其他的类,我们可以通过继承来实现.而在函数式编程中我们也可以采取不同的方式来复用这些函数.今天的教程将会讲述两种方式,其中一个就是组合,将多个函数组合成为一个函数, ...
- 帅呆了!ASP.NET Core每秒能处理115万个请求
今天看到一篇英文博文 -- ASP.NET Core – 2300% More Requests Served Per Second,被震撼了!ASP.NET Core每秒能处理115万个请求(是的, ...
- ASP.NET 5系列教程 (三):view components介绍
在ASP.NET MVC 6中,view components (VCs) 功能类似于虚拟视图,但是功能更加强大. VCs兼顾了视图和控制器的优点,你可以把VCs 看作一个Mini 控制器.它负责控制 ...
- xml Schema import
first_.xsd <?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs=& ...
- [读书笔记]C#学习笔记八:StringBuilder与String详解及参数传递问题剖析
前言 上次在公司开会时有同事分享windebug的知识, 拿的是string字符串Concat拼接 然后用while(true){}死循环的Demo来讲解.其中有提及string操作大量字符串效率低下 ...