一般在C语言中我们使用malloc和free进行内存分配和释放,但是在C++中增加了一个新的
new和delete 操作来进行,按照C++的说法delete是释放内存但是指针得到保留,防止内存
泄露,并且NEW和DELETE要成对出现。我们知道指针本生也是一个保存在内存中某个位置的变量,
如果释放了内存我们是否可以考虑为其中的值得到了删除,而指针自身可以再次指向其他的值?
而还有一点我们需要明白使用NEW分配的内存是HEAP而变量的赋值是栈,
在OS中我们大概可以理解如下(32位系统为例),我这里的共享是指线程是否共享:
4G
kernel --内核内存
3G text --代码文本 共享
data --初始化的全局变量和静态变量 共享
dss --未始化的全局变量和静态变量 共享
栈 --级动态变量数组等 不共享
堆 --malloc 共享
0 共享库 --库文件 mmap 映射 共享
可以看到栈和堆不是一个区域,并且栈始终是自我释放的遵循后入先出原则
我们接下来用如下的小程序带上GDB进行调试
8 #include
9 using namespace std;
10
11
12 int main(void)
13 {
14 int *p; //一个不初始化的指针,不能使用*p=一个INT数字,只能赋予一个指针变量p=(init *)0x130000表示p指针指向130000位置
15 short *b = new short;
16 short *c = new short;
17
18 *b=0X128;
19
20 cout<<"noinit int address is :"<< p <<" "<<sizeof(*p)<<endl;
21 cout<<"short b address is :"<< b <<" "<<sizeof(*b)<<"\n";
22 cout<<"short c address is :"<< c <<" "<<sizeof(*c)<<endl;
23 delete b; //成对出现
24 delete c;
25 //DELETE不释放指针只是释放内存,那么指针指向的内存可以用于其他用途
26 cout<<"init int address is :"<< b <<" "<<sizeof(*b)<<"\n";
27 cout<<"noinit dou address is :"<< c <<" "<<sizeof(*c)<<endl;
28
29 *b=0X256; //直接赋予值,赋值成功
31 delete b; //不成对出现
32 *b=0X512; //便于观察而已
33 delete b; //便于观察,避免指针释放
}
~ 如果我们在
23 delete b;
后去GDB *b的只为0那么说明delete起到了效果
gdb ./a.out
(gdb) b 23
Breakpoint 1 at 0x400a79: file pointer2.cpp, line 23.
(gdb) r
Breakpoint 1, main () at pointer2.cpp:23
23 delete b;
(gdb) p b
$1 = (short *) 0x602010
(gdb) x/2xh 0x602010
0x602010: 0x0128 0x0000
可以看到当前为0X0128数据在这个存储2个字节里面我是也就是0x602010 0x602011
(gdb) n
24 delete c;
(gdb) x/2xh 0x602010
0x602010: 0x0000 0x0000
这里跑完了delete b; 可以看到数据没有了在内存中,继续
继续向下
29 *b=0X256;
(gdb) n
30 delete b;
(gdb) p b
$3 = (short *) 0x602010
这里跑完了 *b=0X256;但是指针位置没有变化,也就是DELETE后指针得到了保留
继续
(gdb) p *b
$4 = 598
(gdb) x/2xh 0x602010
0x602010: 0x0256 0x0000
可以看到数据没有问题。继续看看是否能DELETE
(gdb) n
(gdb) x/2xh 0x602010
0x602010: 0x2020 0x0060
可以看到delete并没有删除数据而已弄了一些垃圾数据进来。
其实这个程序直接跑会报错
*** Error in `./a.out': double free or corruption (fasttop): 0x0000000000f1f010 ***
Aborted (core dumped)
用GDB只是为了找到原因
所以我们必须new和delete 成对使用,否者结果是不确定的,对空指针delete是安全的
delete后指针是得到了保留的没有问题,如果是动态数组将不能使用sizeof来确定他的长度
指针我感觉是使用的栈,同时在函数结束时自我释放。
附带关于GDB的内存查看
转自:http://www.cnblogs.com/super119/archive/2011/03/26/1996125.html
格式: x /nfu
说明
x 是 examine 的缩写
n表示要显示的内存单元的个数
f表示显示方式, 可取如下值
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
i 指令地址格式
c 按字符格式显示变量。
f 按浮点数格式显示变量。
u表示一个地址单元的长度
b表示单字节,
h表示双字节,
w表示四字节,
g表示八字节
Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),
t(binary), f(float), a(address), i(instruction), c(char) and s(string).
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes)
举例
x/3xh buf
表示从内存地址buf读取内容,
h表示以双字节为一个单位,
3表示三个单位,
x表示按十六进制显示
</sizeof(*c)<<endl;
</sizeof(*b)<<"\n";
</sizeof(*c)<<endl;
</sizeof(*b)<<"\n";
</sizeof(*p)<<endl;