目录
内核空间:用户代码不能读写(Linux内核)
栈:向下增长
内存映射:文件映射、动态库、匿名映射
堆:向上增长
数据段:全局、静态
代码段:可执行程序、只读常量(const)
1、为什么要分这些区域:方便管理
2、那些比较重要:堆,因为需要自主控制释放
const修饰的变量不一定就在常量区
const修饰的是变量,而不是常量
const修饰的不是指针,而是修饰的指针指向的内容
检查一个变量地址,需要注意指针和解引用指针的位置
malloc:堆上开空间
calloc:会在malloc的基础上进行初始化
realloc:原地扩容/异地扩容(会把原来空间释放)
C已经有了动态内存管理,为什么还要new呢?
1、malloc和free不够方便:例如需要检查返回值、自己定义空间大小,用法不够简洁等
2、malloc和free对自定义类型的处理简直无能为力,这是致命伤
(因此,再设计一个new,同时,对于内置类型的处理也更加方便,malloc不会调用构造函数,不能初始化)
3、方便自定义类型使用,开空间+调用构造函数
4、new失败,可以自动抛出异常
new语法格式:
int* p1 = new int:在堆上开辟一个int类型的空间
int* p2 = new int[10]:在堆上开辟10个int类型的空间
删除:
delete p1;
delete[] p2;
初始化:
int* p3 = new int(10);
int* p4 = new int[10]{1,2,3,4,5};
-
- //初始化
- int* a1 = new int;
- int* a2 = new int[10];//在堆上开辟一个int类型的空间
- int* a3 = new int(10);//在堆上开辟10个int类型的空间
- int* a4 = new int[10] {1,2,3,4,5};
- //删除
- delete a1;
- delete[] a2;
- delete[] a3;
- delete[] a4;
operator new是对malloc的封装,解决的是malloc失败不会抛出异常的问题,为了实现new
operator delete是对free的封装
他们的用法和malloc用法是一样的
new本质上是,先调用malloc,然后再去调用构造函数
但是,malloc失败会返回空,拿空去调用构造函数,显然不合适
因为面向对象当出现错误时,要抛出异常
因此,为了解决malloc失败返回空的问题,用operator new对malloc进行封装处理,如果失败抛出异常
所以,本质上new还是maoolc,只是处理异常的问题不同而已
new的底层是operator new
operator new的底层是maollc
a、当我们对类显示自定义一个析构函数,在new对象的时,会多new四个字节,存储对象的个数
有了这个数才知道delete析构函数调用几次
b、当没有显示自定义,就不会new一个空间
c、对于delete,先调用析构函数,再调用operator felete
d、内存泄漏不会报错
e、operator 和 operator[]的区别?
后者在类内有自定义析构函数时,会多new四个字节空间,存储对象个数
f、如果delete和delete[]不匹配不适用结果如何?
后果不确定。
后者在free时,会在指针位置往前四个字节,以匹配 operator[]的结果
如果delete匹配的是 operator[],就会报错。
因为,指针位置本应该是往前四个字节,但是现在没有,释放位置错了,报错
如果delete[]匹配 operator,同样,报错
然而,多出四个字节与否,是编译器优化的结果,优化是不可控因素
因此导致,处理结果的不确定
显示调用构造函数
sizeof 运算符 编译时 根据类型大小定义,自定义根据内存对齐规则计算对象大小
在转化成指令时,sizeof不存在,而是替换成一个具体的值
strlen 函数 运行时,在指令时,转化为call
定位new表达式(placement-new)
:new(place_address) type (参数列表)
面试题目:malloc/free和new/delete区别
1、前者是函数,后者是操作符
2、malloc不会初始化,new可以
3、malloc要手动传空间大小,new传类型即可,且可[]指定创建多个对象
4、malloc返回值需要强转,new不需要
5、malloc失败返回空,new抛出异常
6、malloc/free不会调构造析构,new/delete会