C++ 内存管理

1.内存分配的方式有三种:

从静态存储区分配:在程序编译期间已经分配好了,这些在程序的生命周期内都是有效的,如全局变量,static变量

一个例子: char * p = "absd";这个是存储在静态存储区的,而且是不可以改变的,这种方式声明是 const char * p ="asdf";等效的,只是把他给省略了。不可以通过*p去修改他的值,但是p指针是可以指向其他的内存区域。 但是如果是

const char * const p = "asdf";就不可修改p指向的地址,也不可以修改p指向的内容。

在栈上分配内存的方式:函数执行期间,函数内部的局部变量,包括形参都是在堆栈上创建的,当函数结束的时候,这些空间会自动释放(堆栈清退)。这种方式使用的是内置于处理器的指令集,效率十分的高,但是可以分配的内存数量有限。

从堆中分配内存,也就是所谓的动态分配内存。在程序运行期间,使用malloc() or new() 申请一定的内存空间。程序元需要自己掌握内存分配和释放的时机,使用free() or delete.

使用内存分配的原则是:如果使用堆栈存储和静态存储竟可以满足程序的需求的话,就不要使用动态内存分配。

动态内存分配需要调用操作系统的内存管理模块函数,搜索是否有可用的内存空间,开销特别大,同时,场次使用下去,内存会千疮百孔,有大量闲置的内存碎片。同时动态分配内存可能存失败,所以需要补货异常,也需要另外的开销。如果动态分配内存,但是没有释放,就会出现内存泄露。

2.常见的内存分配错误

2.1 内存没有分配成功,是使用之前先检查新申请的内存指针是否是NULL。如果指针作为参数,在函数的入口用assert(p!= NULL);

2.2 内存分配成功,但是尚未初始化,就直接使用,会出现各种以外的错误。

2.3内存分配成功,并且初始化,但是操作内存越界

2.4忘记释放不使用的内存指针,或者只是释放了部分的内存空间,导致内存泄露,最后导致程序的内存溢出。

2.5释放了内存的空间,但是还是继续使用它:

return 语句中返回的指针指向的内容不要是存储在栈中的数据,在函数结束之后,栈中的数据会自动释放。 使用free() or delete 之后最好将指针设置成NULL,否则就会出现野指针,不要多次释放同一块内存空间。

 我们使用指针养成一个习惯

使用new malloc() 申请新的内存的时候,检查是否申请成功,立即使用 if( p==NULL) 判断是否成功申请,放置使用NULL的指针。

分配内存之后,需要初始化内存空间;申请的内存必须对应在不使用的时候释放空间,同时在释放之后,将指针设置成NULL。

3.指针参数传递内存的方式

void getMemory(char * p , int num){

p = (char*) malloc(sizeof(char)* num);

}

char * str = NULL;

getMemory(str,100); // 这个时候,str 依然是NULL

注意使用free(str);释放掉内存空间。

为什么呢?因为在上面的函数中我们使用的是直接传递的参数,而不是使用的引用传递值得方式。这样在函数中,会为p生成一个临时副本_p,这样的,这样的话我们修改的是临时变量_p 而不是变量p,所以在程序中str 依旧是NULL,所以我们需要使用引用的方式传递变量。

void getMemory(char *  &p, int num ){ p= (char*) malloc(sizeof(char)*num);}

getMemory(str, 100);

/*

void getMemory(char ** p, int num){  *p = (char*)malloc(sizeof(char) * num); }

getMemory(&str, 100);

*/

free(str);

str=NULL;

同时我们可以使用返回指针的方式动态分配内存:

char * getMemory(int num){

char *p = (char*) malloc(sizeof(char)* num);

return p;

}

char * str = NULL;

str = getMemory(100);

*str=”yangtengfei”;

函数返回值不要返回栈中的数据,因为在函数结束的时候,就会自动释放掉栈中的变量,所以上面这种方式也会经常出错。

char  * getString(void){ char p[] =”yang”; return p;}

这里返回的p指向的是存储在stack中的数据,当函数结束的时候,就会自动释放掉。返回的是指向一个dirty 的内存区域。

换一种方式

char * getString(void) {char *p = “yahg”; return p;}

char * str = NULL;

str = getString();

这里我们存放的p指向的内容是存放在静态存储区的而且这种方式是不可以被改变的。每一次访问函数,都是在静态存储区域获取该字符串的。

4. free and delete 操作指针

当我们动态分配内存空间,然后使用free或者delete,对指针指向的内容释放,但是指针本身还是指向这一块内存区域,也就是我们所说的野指针。所以我么当释放掉指针指向内容的空间后,需要将指针置为NULL。

5.动态内存会不会被自动释放

函数中的局部变量在函数结束的时候,就会自动结束,但是对于指针变量指向的内存空间不会自动消亡:

void fun(void){char *p = (char*) malloc(100);}

当函数结束的时候,变量p 是消亡了,但是变量 p 指针指向的内存空间并不会随着变量指针p的消亡而消亡;同时内存被释放了,但是并不代表指针会消亡,或者是指针指向NULL。

6.杜绝野指针

野指针就是指向非法内存的指针,而不是NULL指针,对于野指针,我们无法判断,所以是很危险的,我们在程序中避免出现野指针的情况:

1.没有初始化的指针变量,任何指针变量声明之后,是不会被初始化为NULL,他的默认值是随机的,所以在创建指针的同时应该初始化指针,让他指向有意义的内存,或者是NULL;

2.当使用free(p) 或者是delete p;之后,没有设置指针NULL,p任然指向的是该内存区域,所以是一个野指针。

3.指针超过了变量的作用范围:

class A {};

A *p = NULL;

{

A a;

P = &a;

}

p->fun(); //p已经失效了 虽然运行不会出错,但是对于大的项目,很悲剧,肯呢过出现错误。

7. malloc / free  & new /delete

C/C++ 使用 malloc / free  C++中的类使用的是 new and delete

对象创建的时候需要调用构造函数,对象销毁的时候需要自动的调用析构函数,因为malloc/free是库函数而不是运算符,所以控制权不是在编译器内,所以不可以吧调用构造函数或者析构函数的任务交给他们,这个时候需要使用C++的 new delete他们不是库函数,而是使用语言实现的运算符。

使用new 和delete更加安全,new 可以自动计算他要构造对象的空间,但是malloc不可以。new直接返回的就是类型的指针,但是malloc需要显示的转化返回的void*指针到指定的指针类型。

new/delete 可以被重载实现,但是malloc/free是不可以的。

相比之下malloc/free更加高效。

8.malloc/free

void * malloc(size_t size);

malloc返回的类型是void*,所以在使用malloc的时候需要显示的转换指针的类型,对于malloc关注的只是分配内存的空间而不是类型,所以最好在使用malloc的时候,配合sizeof()函数使用。

int *p = (int*) malloc(sizeof(int)* length);

free 函数原型

void free(void * memblock);

对于同一个内存地址空间,使用free只可以释放一次,之后再释放回出错。而对于NULL的指针,可以使用free任意次。

9.new使用的几种方式

plain new/delete:就是普通的方式new一个空间,对于普通的new如果失败的话,返回的是NULL,但是plain new 会分配内存失败的时候抛出std::bad_alloc异常。

nothrow new /delete: 就是不会抛出异常的new

10new/delete 要点

不论何种类型的new/delete new[]/ delete[] 都应该配对使用,放置内存泄露。对于动态创建的数组,使用delete p 和 delete []p 效果是一样的。

多次delete一个不是NULL的指针会导致运行的时候出错,但是多次delete NULL pointer是没有问题的,因为在delete之前会检查指针是否是NULL,如果是的话,直接返回。

11.内存耗尽

处理内存耗尽的情况:

检查指针是否是NULL,如果是的话,直接return终止函数的运行;

或者当检查到指针式NULL,则直接exit(1) 程序。

捕获new抛出的异常,并且处理该异常,尝试恢复。

C++复习1.内存管理的知识的更多相关文章

  1. iOS内存管理的知识梳理

    从作用上来说,手机内存小,划分给每个App的内存有限,合理的进行内存管理,有利于提高软件的运行性能和用户体验: 另外,内存管理是一大理论知识块,对这块知识的理解程度也是考核面试者的重要标准. 内存管理 ...

  2. C++复习12.程序内存管理

    程序内存管理 20131006 一个程序在运行期间的内存是如何的对编写程序至关重要,之前整理的C++内存管理的知识和Java程序内存管理的知识.今天我们系统的整理一下程序的内存. 1.一个程序的内存有 ...

  3. 嵌入式linux学习笔记1—内存管理MMU之虚拟地址到物理地址的转化

    一.内存管理基本知识 1.S3C2440最多会用到两级页表:以段的方式进行转换时只用到一级页表,以页的方式进行转换时用到两级页表.页的大小有三种:大页(64KB),小页(4KB),极小页(1KB).条 ...

  4. Spark(二): 内存管理

    Spark 作为一个以擅长内存计算为优势的计算引擎,内存管理方案是其非常重要的模块: Spark的内存可以大体归为两类:execution和storage,前者包括shuffles.joins.sor ...

  5. Cocos2d-x开发中C++内存管理

    由于开始并没有介绍C++语言,C++的内存管理当然也没进行任何的说明,为了掌握Cocos2d-x中的内存管理机制,是有必要先了解一些C++内存管理的知识.C++内存管理非常复杂,如果完全地系统地介绍可 ...

  6. 深入java虚拟机学习 -- 内存管理机制

    前面说过了类的加载机制,里面讲到了类的初始化中时用到了一部分内存管理的知识,这里让我们来看下Java虚拟机是如何管理内存的. 先让我们来看张图 有些文章中对线程隔离区还称之为线程独占区,其实是一个意思 ...

  7. Theano教程:Python的内存管理

    在写大型程序时候的一大挑战是如何保证最少的内存使用率.但是在Python中的内存管理是比较简单的.Python显示分配内存,使用引用计数系统管理对象,当指向某一个对象的引用数变为 0 的时候,该对象所 ...

  8. 你真的了解Python吗 ---Python的内存管理

    请看下面的一段代码: origin = {'a':100,'b':[1,2,34,5]} obj_copy ={}; print origin; obj_copy['key1']= origin; o ...

  9. Python的内存管理 小理解

    请看下面的一段代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 origin = {'a':100,'b':[1,2,34,5]} obj_copy ={}; ...

随机推荐

  1. iClap:更智能的场景化工作方式

    8月31日,移动互联网企业运营解决方案整合平台DevStore团队正式推出新品——产品管理系统iClap,iClap集成了智能任务管理.Bug跟踪.简单发布.人才培养等功能,同时推出普通版和旗舰版两个 ...

  2. 基于Python操作redis介绍

    (注:本文部分内容摘自互联网,由于作者水平有限,不足之处,还望留言指正.) 毕业前的最后一个学期(2016.03),龙哥结婚了.可是总有些人喜欢嘲笑别人,调侃我.当时我就理直气壮的告诉他们,等龙哥孩子 ...

  3. Decker容器使用

    Docker 客户端 我们可以直接输入 docker 命令来查看到 Docker 客户端的所有命令选项 root@ranxf:/home/ranxf# docker Usage: docker COM ...

  4. Django学习笔记之Django的url反向解析

    0x00 URL反向解析和三种不同的反向解析方式 Django中提供了关于URL的映射的解决方案,可以做两个方向的使用: 1.普通解析过程:由客户端的浏览器发起一个url请求,Django根据URL解 ...

  5. GoEasyWeb实时推送

    GoEasyWeb实时推送,轻松实现实时消息推送. Web页面订阅(约5行代码),服务器端推送(2行代码)就可以轻松实现,而且在高并发时消息推送稳定. 自己完全可以只花五分钟写出属于自己的第一个实时推 ...

  6. 20145309《Java程序设计》第七周学习总结

    教材学习内容总结 第13章 时间与日期 13.1 认识时间与日期 13.1.1 时间的度量 格林威治时间(GMT) 世界时(UT) 国际原子时(TAI) 世界协调时间(UTC) Unix时间:Unix ...

  7. 快速升级openwrt的linux内核版本

    一.分析 要升级openwrt的linux内核版本,关键是要制作内核配置文件 二.内核配置文件制作方法 2.1当前openwrt对应的某个开发板有对应的内核配置文件,比如此时的openwrt的linu ...

  8. [CF911F]Tree Destruction

    题意翻译 给你一棵树,每次挑选这棵树的两个叶子,加上他们之间的边数(距离),然后将其中一个点去掉,问你边数(距离)之和最大可以是多少. 首先我们知道,到一个点距离最远的点是直径的端点.考虑贪心,如果我 ...

  9. 大端和小端(big endian little endian)

    一.大端和小端的问题 对于整型.长整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节):而 Little endian 则相反,它 ...

  10. MySQL 常用运算符

    1.算数运算符 加 mysql> select 1+2; 减 mysql> select 2-1; 乘 mysql> select 2*3; 除 mysql> select 5 ...