基本思想:最近做项目,遇到了在android上使用c++开发时,内存泄漏和内存释放失败的情况,顾复习一下之前的知识点,顺手也记录一下;

提供一个demo和简单的分析叙述;

#include<iostream>
#include<vector>
using namespace std;
typedef struct
{
int x;
int y;
} Point;


class Axis
{
public:
Axis()
{}
~Axis()
{
avpoint.clear();
vector<Point>().swap(avpoint);
cout << "after swap size:" << avpoint.size() << endl;
cout << "after swap capacity:" << avpoint.capacity() << endl;
for(int i=0;i<avpppoint.size();i++)
{
if(NULL!=avpppoint[i]){
delete avpppoint[i];
avpppoint[i]=NULL;
}
}
avpppoint.clear();
vector<Point*>().swap(avpppoint);

cout << "after swap size:" << avpppoint.size() << endl;
cout << "after swap capacity:" << avpppoint.capacity() << endl;

}
private:
int x;
int y;
vector<Point> avpoint;
vector<Point*> avpppoint;
public:
void setx(int x)
{this->x=x;
}
void sety(int y)
{this->y=y;
}
void init()
{
Point pp;
pp.x=99;
pp.y=999;
avpoint.push_back(pp);
Point *vppoint=new Point();
vppoint->x=33;
vppoint->y=43;
avpppoint.push_back(vppoint);
}
};

int main()
{
vector<int> v;
for(int i=0;i<72;i++)
{
v.push_back(i);
}

cout << "size:" << v.size() << endl;
cout << "capacity:" << v.capacity() << endl;
v.clear();
vector<int>().swap(v);
cout << "after swap size:" << v.size() << endl;
cout << "after swap capacity:" << v.capacity() << endl;
//
vector<Point> vp;
Point point;
for(int i=0;i<4;i++)
{
point.x=i;
point.y=i;
vp.push_back(point);
}


vp.clear();
vector<Point>().swap(vp);
cout << "size:" << vp.size() << endl;

cout << "capacity:" << vp.capacity() << endl;

vector<Axis*> vaxis;
Axis *axis=new Axis();
axis->setx(1);
axis->sety(2);
vaxis.push_back(axis);
vaxis.clear();
vector<Axis*>().swap(vaxis);
delete axis;
cout << "size:" << vaxis.size() << endl;
cout << "capacity:" << vaxis.capacity() << endl;


Axis *bxis=new Axis();
bxis->init();
delete bxis;




return 0;
}

执行结果

ubuntu@ubuntu:~/test$ ./a.out
size:72
capacity:128
after swap size:0
after swap capacity:0
size:0
capacity:0
after swap size:0
after swap capacity:0
after swap size:0
after swap capacity:0
size:0
capacity:0
after swap size:0
after swap capacity:0
after swap size:0
after swap capacity:0

内存检查valgrind  (简单说明 我是用的gcc-5.4 valgrind 3-13 ; 编译器版本和内存检查工具不同 生成的valgrind的报告存在差异,差异在于是否输出内存池的的log信息,关于内存池的相关知识,请参考相关文档)

ubuntu@ubuntu:~/test$ G_SLICE=always-malloc G_DEBUG=gc-friendly valgrind --tool=memcheck --leak-check=full --leak-resolution=high --num-callers=20 --show-reachable=yes --log-file=a.log  ./a.out
size:72
capacity:128
after swap size:0
after swap capacity:0
size:0
capacity:0
after swap size:0
after swap capacity:0
after swap size:0
after swap capacity:0
size:0
capacity:0
after swap size:0
after swap capacity:0
after swap size:0
after swap capacity:0

内存检查的log

ubuntu@ubuntu:~/test$ cat a.log
==41010== Memcheck, a memory error detector
==41010== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==41010== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==41010== Command: ./a.out
==41010== Parent PID: 22172
==41010==
==41010==
==41010== HEAP SUMMARY:
==41010== in use at exit: 72,704 bytes in 1 blocks
==41010== total heap usage: 19 allocs, 18 frees, 74,948 bytes allocated
==41010==
==41010== 72,704 bytes in 1 blocks are still reachable in loss record 1 of 1
==41010== at 0x4C2DBF6: malloc (vg_replace_malloc.c:299)
==41010== by 0x4EC3EFF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==41010== by 0x40106C9: call_init.part.0 (dl-init.c:72)
==41010== by 0x40107DA: call_init (dl-init.c:30)
==41010== by 0x40107DA: _dl_init (dl-init.c:120)
==41010== by 0x4000C69: ??? (in /lib/x86_64-linux-gnu/ld-2.23.so)
==41010==
==41010== LEAK SUMMARY:
==41010== definitely lost: 0 bytes in 0 blocks
==41010== indirectly lost: 0 bytes in 0 blocks
==41010== possibly lost: 0 bytes in 0 blocks
==41010== still reachable: 72,704 bytes in 1 blocks
==41010== suppressed: 0 bytes in 0 blocks
==41010==
==41010== For counts of detected and suppressed errors, rerun with: -v
==41010== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

其中这段信息的含义:

==41010== 72,704 bytes in 1 blocks are still reachable in loss record 1 of 1
==41010== at 0x4C2DBF6: malloc (vg_replace_malloc.c:299)
==41010== by 0x4EC3EFF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==41010== by 0x40106C9: call_init.part.0 (dl-init.c:72)
==41010== by 0x40107DA: call_init (dl-init.c:30)
==41010== by 0x40107DA: _dl_init (dl-init.c:120)
==41010== by 0x4000C69: ??? (in /lib/x86_64-linux-gnu/ld-2.23.so)

摘录他人的叙述:

“使用 Valgrind 分析 C++ 程序时,有一些问题需要留意。例如,这个程序并没有发生内存泄漏,但是从​​HEAP SUMMARY​​可以看到,程序分配了 2 次内存,但却只释放了 1 次内存,为什么会这样呢?

实际上这是由于 C++ 在分配内存时,为了提高效率,使用了它自己的内存池。当程序终止时,内存池的内存才会被操作系统回收,所以 Valgrind 会将这部分内存报告为 reachable 的,需要注意,reachable 的内存不代表内存泄漏,例如,从上面的输出中可以看到,有 72704 个字节是 reachable 的,但没有报告内存泄漏。”