8, 堆,栈,内存管理



栈:  local objects 在离开作用域之后就会被消除. 
堆: new MyClass 一直会存在
静态对象: static local object    作用域在当前函数,其生命在整个程序结束后才会结束. 
全局对象: Global object           作用域在全局.


new函数的内部实现: 
e.g Complex * pc = new Complex(1,2);

分解: 
1, void* mem = operator new(sizeof(Complex));    -分配内存 使用molloc实现
2, pc = static_cast<Complex*>(mem);     - 转型
3, pc->Complex::Complex(1,2);       - 构造函数

delete函数的内部实现: 
e.g delete pc;

分解:
1, String::~String(pc);        -析构函数
2, operator delete(pc);      -释放内存 内部使用free实现


动态分配得到的内存块:
debug:
头尾: cookie (小甜饼干) 4x2
复数 : 8b
最终加起来得到的内存块为 52b
但是在vc下, 每个内存块分配都是16的倍数.
所以,这里需要填补(pad) 得到64


release: 

正好是16的倍数.

cookie说明:
cookie的作用是记录整块分配内存的大小.
因为都是16的倍数,所以最后有4个为是空的. 所以最后那位我们可以使用.
当最后一位是1时,说明是系统分配给我们的. 
如果我们要把内存还给系统,那么最后一位就会变成0.


vc中动态分配数组
debug:


8*3是数据
32+4是调试相关字符
4*2是cookie
最后的4是数组的大小 保存数据'3'
最后80是要向16对齐.


release:

内存泄露不是我们所以为的内存泄露:

array new 一定要搭配array delete 

e.g String* p = new String[3];

delete[] p;    -唤起3次析构函数 
delete p;      -唤起1次析构函数

无论上面哪种方式,都会删除cookie中间的那块内存. 
所以问题是出现在里面保存对象是否调用了析构函数. 
各自的析构就会负责把自己动态分配的内存删除掉. 
所以, 如果数组中的对象不含有指针.所以只用delete也是可以的,也不会造成内存泄露. 

疑问:
为什么系统不直接根据 那个'3'字节来将全部对象调用析构? 而是非得要求用户调用delete[]




9,复习String类的实现

strlen取得的长度不含'\0'

在拷贝赋值中, 返回类型尽量使用 MyClass& MyClass::operator=(const MyClass&  m2) !
而不是void MyClass::operator=(const MyClass&  m2)  
使用void在一般情况: m1 = m2 这样的一个赋值上是没有问题的. 但, 当一连串赋值的时候就必须使用返回引用了! ! !  ! 
这就贯彻了之前说过的 "调用者无需知道函数是使用什么方式传递出去的"


一定要注意 取地址符号&和引用符号&的区分! 





10, 拓展补充

static 关键字

静态数据 
MyClass{
static int count;    //-  无论创造多少个对象,  这个变量只有一份. 
static void Set_Count(int cc) { count  = cc;}
};
注意: 静态变量 一定要在类外进行定义(我们俗称初始化);
int MyClass::count = 10;    //格式一定要注意! 前面的类型一定要写!后面要不要赋值不是必要.


静态函数调用方式: 
1,通过对象来调用:
MyClass  my;
my.Set_Count(2);
2,通过类名来调用:
MyClass::Set_Count(3);


单例模式:
把构造函数放在private区内. 这样就不能通过普通模式构建对象, 此时再声明一个静态成员函数,用于返回一个实例化对象. 





8, 堆,栈,内存管理



栈:  local objects 在离开作用域之后就会被消除. 
堆: new MyClass 一直会存在
静态对象: static local object    作用域在当前函数,其生命在整个程序结束后才会结束. 
全局对象: Global object           作用域在全局.


new函数的内部实现
e.g Complex * pc = new Complex(1,2);

分解: 
1, void* mem = operator new(sizeof(Complex));    -分配内存 使用molloc实现
2, pc = static_cast<Complex*>(mem);     - 转型
3, pc->Complex::Complex(1,2);       - 构造函数

delete函数的内部实现
e.g delete pc;

分解:
1, String::~String(pc);        -析构函数
2, operator delete(pc);      -释放内存 内部使用free实现


动态分配得到的内存块:
debug:

头尾: cookie (小甜饼干) 4x2
复数 : 8b
最终加起来得到的内存块为 52b
但是在vc下, 每个内存块分配都是16的倍数.
所以,这里需要填补(pad) 得到64


release: 

正好是16的倍数.

cookie说明:
cookie的作用是记录整块分配内存的大小.
因为都是16的倍数,所以最后有4个为是空的. 所以最后那位我们可以使用.
当最后一位是1时,说明是系统分配给我们的. 
如果我们要把内存还给系统,那么最后一位就会变成0.


vc中动态分配数组
debug:

8*3是数据
32+4是调试相关字符
4*2是cookie
最后的4是数组的大小 保存数据'3'
最后80是要向16对齐.


release:


内存泄露不是我们所以为的内存泄露:

array new 一定要搭配array delete 


e.g String* p = new String[3];

delete[] p;    -唤起3次析构函数 
delete p;      -唤起1次析构函数

无论上面哪种方式,都会删除cookie中间的那块内存. 
所以问题是出现在里面保存对象是否调用了析构函数. 
各自的析构就会负责把自己动态分配的内存删除掉. 
所以, 如果数组中的对象不含有指针.所以只用delete也是可以的,也不会造成内存泄露. 

疑问:
为什么系统不直接根据 那个'3'字节来将全部对象调用析构? 而是非得要求用户调用delete[]




9,复习String类的实现

strlen取得的长度不含'\0'

在拷贝赋值中, 返回类型尽量使用 MyClass& MyClass::operator=(const MyClass&  m2) !
而不是void MyClass::operator=(const MyClass&  m2)  
使用void在一般情况: m1 = m2 这样的一个赋值上是没有问题的. 但, 当一连串赋值的时候就必须使用返回引用了! ! !  ! 
这就贯彻了之前说过的 "调用者无需知道函数是使用什么方式传递出去的"


一定要注意 取地址符号&和引用符号&的区分! 





10, 拓展补充

static 关键字

静态数据 
MyClass{
static int count;    //-  无论创造多少个对象,  这个变量只有一份. 
static void Set_Count(int cc) { count  = cc;}
};
注意: 静态变量 一定要在类外进行定义(我们俗称初始化);
int MyClass::count = 10;    //格式一定要注意! 前面的类型一定要写!后面要不要赋值不是必要.


静态函数调用方式: 
1,通过对象来调用:
MyClass  my;
my.Set_Count(2);
2,通过类名来调用:
MyClass::Set_Count(3);


单例模式:
把构造函数放在private区内. 这样就不能通过普通模式构建对象, 此时再声明一个静态成员函数,用于返回一个实例化对象. 




堆,栈,内存管理, 拓展补充-Geekband的更多相关文章

  1. cassandra 堆外内存管理

    为什么需要堆外内存呢 单有一些大内存对象的时候,JVM进行垃圾回收时需要收集所有的这些对象的内存也.增加了GC压力.因此需要使用堆外内存. java 分配堆外内存 org.apache.cassand ...

  2. Java堆外内存管理

    Java堆外内存管理   1.JVM可以使用的内存分外2种:堆内存和堆外内存: 堆内存完全由JVM负责分配和释放,如果程序没有缺陷代码导致内存泄露,那么就不会遇到java.lang.OutOfMemo ...

  3. Java堆外内存之五:堆外内存管理类ByteBuffer

    本篇主要讲解如何使用直接内存(堆外内存),并按照下面的步骤进行说明: 相关背景-->读写操作-->关键属性-->读写实践-->扩展-->参考说明 希望对想使用直接内存的朋 ...

  4. Java 堆内存与栈内存异同(Java Heap Memory vs Stack Memory Difference)

    --reference Java Heap Memory vs Stack Memory Difference 在数据结构中,堆和栈可以说是两种最基础的数据结构,而Java中的栈内存空间和堆内存空间有 ...

  5. Java堆内存与栈内存对比

    在数据结构中,堆和栈可以说是两种最基础的数据结构,而Java中的栈内存空间和堆内存空间有什么异同,以及和数据结构中的堆栈有何关系? 一.Java 堆存储空间 堆内存(堆存储空间)会在Java运行时分配 ...

  6. Linux C 堆内存管理函数malloc()、calloc()、realloc()、free()详解

    C 编程中,经常需要操作的内存可分为下面几个类别: 堆栈区(stack):由编译器自动分配与释放,存放函数的参数值,局部变量,临时变量等等,它们获取的方式都是由编译器自动执行的 堆区(heap):一般 ...

  7. C++内存管理4-Windows编程中的堆管理(转)

    1 引言 在大多数Windows应用程序设计中,都几乎不可避免的要对内存进行操作和管理.在进行大尺寸内存的动态分配时尤其显的重要.本文即主要对内存管理中的堆管理技术进行论述. 堆(Heap)实际是位于 ...

  8. 内存管理之堆heap

    1.什么是堆? 堆(heap)是一种内存管理方式.内存管理对操作系统来说是一件非常复杂的事情,因为首先内存容量很大, 其次就是内存需求在时间和大小块上没有规律(操作系统上运行着几十甚至几百个进程,这些 ...

  9. C#下内存管理--垃圾收集

    章节安排 内存管理简介 垃圾回收机制 性能问题 C#下非托管资源的处理 要强调的几点 References 内存管理简介 对于任何一种编程语言,内存管理都是不得不提很重要的一块内容,但可惜的是目前为止 ...

随机推荐

  1. nginx 知识

    nginx如何实现高并发? 启动nginx服务器后,输入 ps -ef |grep nginx,会发现nginx有一个master进程 和若干个worker进程, 这些worker进程是平等的,都是被 ...

  2. python库之sklearn

     一.安装sklearn conda install scikit-learn 参考文献 [1]整体介绍sklearn https://blog.csdn.net/u014248127/article ...

  3. 区别 |峰度(Kurtosis)和偏度(Skewness)

      峰度(Kurtosis) 定义 峰度又称峰态系数,表征概率密度分布曲线在平均值处峰值高低的特征数,即是描述总体中所有取值分布形态陡缓程度的统计量.直观看来,峰度反映了峰部的尖度.这个统计量需要与正 ...

  4. Open CV 环境配置

    { //https://github.com/zhmmmm/ANYTOOL-2.0.0.0.2Version/tree/master/OpenCVProject } /* //各个版本下载 https ...

  5. Mysql优化系列之查询性能优化前篇3(必须知道的几个事实)

    事实一:临时表没有任何索引 最常见的临时表莫过于在from子句中写子查询,遇到这种情况,Mysql会先将其查询结果放到一张临时表中, 然后将这个临时表当做普通表对待 事实二:执行计划优化 大多数的sq ...

  6. 19.SimLogin_case05

    # 使用自造的cookies登录马蜂窝 import requests from lxml import etree str = 'mfw_uuid=5bcfcc20-b235-fbbe-c1d6-a ...

  7. 面试系列 30 如何自己设计一个类似dubbo的rpc框架

    其实一般问到你这问题,你起码不能认怂,因为既然咱们这个课程是短期的面试突击训练课程,那我不可能给你深入讲解什么kafka源码剖析,dubbo源码剖析,何况我就算讲了,你要真的消化理解和吸收,起码个把月 ...

  8. ps photoshop

    PS-前端切图教程(切jpg图和切png图) 参考线显示和隐藏:ctrol+h alt+v+e或者打开标尺然后从点击标尺就能拖拽出来,删除也是拖到标尺附近就删除 显示.隐藏标尺:ctrol+R 显示网 ...

  9. Kill- Linux必学的60个命令

    1.作用 kill命令用来中止一个进程. 2.格式 kill [ -s signal | -p ] [ -a ] pid ... kill -l [ signal ] 3.参数 -s:指定发送的信号. ...

  10. python全栈开发:字符串格式化

    Python的字符串格式化有两种方式: 百分号方式.format方式百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存. 1.百分号方式 %[(name ...