C++内存管理学习笔记(7) (一)

2014-11-24 00:33:29 · 作者: · 浏览: 10

/****************************************************************/

/* 学习是合作和分享式的!

/* Author:Atlas /* 转载请注明本文出处:

/****************************************************************/

上期内容回顾:

C++内存管理学习笔记(6)

3 内存泄漏 3.1 引入-一个内存泄漏的解决方案 3.2 如何对付内存泄漏 3.3 浅谈c++内存泄漏及检测工具


--------------------------------------------------------------------------------
3.3.3 检测内粗泄漏的工具介绍
在《C/C++内存泄漏及检测》一文中,作者简单的介绍了下在Windows、Linux下面的内存检测。这里我将大致内容引用过来,增加对内存管理中内存泄漏部分的理解。目前笔者主要是在Linux下作一些开发应用,所主要说明在linux平台下的方式,其实这不同平台下原理相同形式不同而已。

首先,来看一个简单的内存泄漏例子,虽然最后函数结束会被释放掉,如果此时while(1),则内存会耗尽

1: #include 2: #include 3: 4: usingnamespacestd; 5: 6: void GetMemory(char*p, intnum) 7: { 8: p = (char*)malloc(sizeof(char) * num);//使用new也能够检测出来 9: } 10: int main(intargc,char** argv) 11: { 12: char *str = NULL; 13: GetMemory(str, 100); 14: cout<<"Memory leak test!"<

Linux平台下,原理理大致如下:要在分配内存和释放内存时分别做好记录,程序结束时对比分配内存和释放内存的记录就可以确定是不是有内存泄漏。此处作者推荐了linux下mtrace工具,以及另外一个非常强大的工具valgrind,

image

如上图所示知道:

==6118== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==6118== at 0x4024F20: malloc (vg_replace_malloc.c:236)
==6118== by 0x8048724: GetMemory(char*, int) (in /home/netsky/workspace/a.out)
==6118== by 0x804874E: main (in /home/netsky/workspace/a.out)

是在main中调用了GetMemory导致的内存泄漏,GetMemory中是调用了malloc导致泄漏了100字节的内存。

Things to notice:
There is a lot of information in each error message; read it carefully.
The 6118 is the process ID; it’s usually unimportant.
The rst line ("Heap Summary") tells you what kind of error it is.
Below the rst line is a stack trace telling you where the problem occurred. Stack traces can get quite large, and be confusing, especially if you are using the C++ STL. Reading them from the bottom up can help.

The code addresses (eg. 0x4024F20) are usually unimportant, but occasionally crucial for tracking down weirder bugs.The stack trace tells you where the leaked memory was allocated. Memcheck cannot tell you why the memory leaked, unfortunately. (Ignore the "vg_replace_malloc.c", that’s an implementation detail.) There are several kinds of leaks; the two most important categories are:
"de nitely lost": your program is leaking memory -- x it!
"probably lost": your program is leaking memory, unless you’re doing funny things with pointers (such as moving
them to point to the middle of a heap block)

3.4 关于内存回收这件事
内存回收是确保内存不泄露的有效机制。

(1)三种内存对象的分析

栈对象的优势是在适当的时候自动生成,又在适当的时候自动销毁,不需要程序员操心;而且栈对象的创建速度一般较堆对象快,因为分配堆对象时,会调用operator new操作,operator new会采用某种内存空间搜索算法,而该搜索过程可能是很费时间的,产生栈对象则没有这么麻烦,它仅仅需要移动栈顶指针就可以了。但是要注意的是,通常栈空间容量比较小,一般是1MB~2MB,所以体积比较大的对象不适合在栈中分配。特别要注意递归函数中最好不要使用栈对象,因为随着递归调用深度的增加,所需的栈空间也会线性增加,当所需栈空间不够时,便会导致栈溢出,这样就会产生运行时错误。

堆对象,其产生时刻和销毁时刻都要程序员精确定义,也就是说,程序员对堆对象的生命具有完全的控制权。我们常常需要这样的对象,比如,我们需要创建一个对象,能够被多个函数所访问,但是又不想使其成为全局的,那么这个时候创建一个堆对象无疑是良好的选择,然后在各个函数之间传递这个堆对象的指针,便可以实现对该对象的共享。另外,相比于栈空间,堆的容量要大得多。实际上,当物理内存不够时,如果这时还需要生成新的堆对象,通常不会产生运行时错误,而是系统会使用虚拟内存来扩展实际的物理内存。

接下来看看static对象:

首先是全局对象。全局对象为类间通信和函数间通信提供了一种最简单的方式,虽然这种方式并不优雅。一般而言,在完全的面向对象语言中,是不存在全局对象的,比如C#,因为全局对象意味着不安全和高耦合,在程序中过多地使用全局对象将大大降低程序的健壮性、稳定性、可维护性和可复用性。C++也完全可以剔除全局对象,但是最终没有,我想原因之一是为了兼容C。

其次是类的静态成员,上面已经提到,基类及其派生类的所有对象都共享这个静态成员对象,所以当需要在这些class之间或这些class objects之间进行数据共享或通信时,这样的静态成员无