- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章c++ 排查内存泄漏的妙招由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
对于c++而言,如何查找内存泄漏是程序员亘古不变的话题;解决之道可谓花样繁多。因为最近要用到QT写程序,摆在我面前的第一个重要问题是内存防泄漏。如果能找到一个简单而行之有效的方法,对后续开发大有裨益。久思终得诀窍,本文就详细介绍我对此问题的应对之策。(文末符完整代码) 。
内存分配和释放对应的操作是new、delete。如何判断内存是否释放干净?其实判断起来非常简单:一个独立的模块整个生存周期内new的个数和delete的个数相等。用伪代码标示如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
int
newCount = 0;
int
deleteCount = 0;
//new 操作时
new
class
();
newCount++;
//delete 操作时
delete
* objPtr;
deleteCount++;
//模块结束时
if
(newCount != deleteCount)
{
内存有泄漏
}
|
如果对所有的new和delete操作,加上如上几行代码,就能发现是否有内存泄漏问题。如果采用上面方法解决问题,手段太low了.
1 使用起来超级简单,不增加开发难度.
2 发生内存泄漏时,能定位到具体是哪个类.
要跟踪所有的new、delete操作,最简单的办法就是托管new、delete。不直接调用系统的操作符,而是用我们自己写的函数处理。在我们的函数内部,则别有洞天; 对new和delete的跟踪和记录就为我所欲也。托管new和delete需用到模板函数,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
class
MemManage
{
//单实例模式
private
:
static
MemManage* _instance_ptr;
public
:
static
MemManage* instance()
{
if
(_instance_ptr == nullptr)
{
_instance_ptr =
new
MemManage();
}
return
_instance_ptr;
}
public
:
MemManage();
//new操作 构造函数没有参数
template
<
typename
T>
T* New()
{
ShowOperationMessage<T>(
true
);
return
new
T();
};
//new操作 构造函数有1个参数
template
<
typename
T,
typename
TParam1>
T* New(TParam1 param)
{
ShowOperationMessage<T>(
true
);
return
new
T(param);
};
//new操作 构造函数有2个参数
template
<
typename
T,
typename
TParam1,
typename
TParam2>
T* New(TParam1 param1, TParam2 param2)
{
ShowOperationMessage<T>(
true
);
return
new
T(param1, param2);
};
//delete 操作
template
<
typename
T>
void
Delete(T t)
{
if
(t == nullptr)
return
;
ShowOperationMessage<T>(
false
);
delete
t;
};
//记录new delete
template
<
typename
T>
void
ShowOperationMessage(
bool
isNew)
{
//操作符对应的类名称
const
type_info& nInfo =
typeid
(T);
QString className = nInfo.name();
if
(isNew)
{
_newCount++;
}
else
{
_deleteCount++;
}
if
(!_showDetailMessage)
{
return
;
}
if
(isNew)
{
qDebug() <<
"*New"
<< className <<
":"
<< _newCount <<
":"
<< _deleteCount;
}
else
{
qDebug() <<
"Delete"
<< className <<
":"
<< _newCount <<
":"
<< _deleteCount;
}
}
}
|
使用起来很简单,示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//*****new和delete使用伪代码
//new操作,需根据构造函数的参数个数调用对应的函数
//构造函数 没有参数
QFile* file = MemManage::instance()->New<QFile>();
//构造函数 有1个参数
QFile* file = MemManage::instance()->New<QFile, QString>(
"filename"
);
//构造函数 有2个参数
QFile* file = MemManage::instance()->New<QFile, QString,
bool
>(
"filename"
,
true
);
//delete 只有一种形式
MemManage::instance()->Delete(file);
|
一个模块调用周期结束 调用下列代码,查看是否有内存泄漏:
1
2
3
4
5
6
7
8
9
10
|
void
ShowNewDelete(
bool
isShowDetail)
{
int
leftNew = _newCount - _deleteCount;
qDebug() <<
"***********************"
;
qDebug() <<
"total New:"
<< _newCount <<
" Delete:"
<< _deleteCount <<
" leftNew:"
<< leftNew;
}
MemManage::instance()->ShowNewDelete(
true
);
//debug输出如下,如果leftNew为0,则没内存泄漏
total New : 166 Delete : 6 leftNew : 160
|
通过判断new和delete的个数是否相等,只是知道了是否有内存泄漏;进一步定位问题,才能方便我们解决问题。如果能定位到操作哪一个类时,发生了内存泄漏,则问题范围就大大缩小。我们可以按类名,记录new和delete操作个数,c++获取类名函数如下:
1
2
|
const
type_info &nInfo =
typeid
(T);
QString className = nInfo.name();
|
建立一个map表,记录类名对应的操作信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
//每个类 统计的信息
class
MemObjInfo
{
public
:
int
NewCount = 0;
int
DeletCount = 0;
QString ClassName;
};
//map对照表
QMap<QString, MemObjInfo*> _mapMemObjCount;
//按类名统计
void
AddCount(QString& className,
bool
isNew)
{
QMap<QString, MemObjInfo*>::ConstIterator i = _mapMemObjCount.find(className);
if
(i == _mapMemObjCount.constEnd())
{
MemObjInfo* info =
new
MemObjInfo();
info->ClassName = className;
if
(isNew)
{
info->NewCount++;
}
else
{
info->DeletCount++;
}
_mapMemObjCount.insert(className, info);
}
else
{
MemObjInfo* info = i.value();
if
(isNew)
{
info->NewCount++;
}
else
{
info->DeletCount++;
}
}
}
|
如果有内存泄漏 则会输出如下信息:
如上图,对5个类的操作发送了内存泄漏。比如我们知道了类OfdDocumentPageAttr发生内存泄漏,就很容易定位问题了.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
#ifndef MEMMANAGE_H
#define MEMMANAGE_H
#include <QDebug>
#include <QList>
#include <QMutex>
class
LockRealse
{
public
:
LockRealse(QMutex* mutex)
{
_mutex = mutex;
_mutex->lock();
}
~LockRealse()
{
_mutex->unlock();
}
private
:
QMutex* _mutex;
};
class
MemObjInfo
{
public
:
int
NewCount = 0;
int
DeletCount = 0;
QString ClassName;
};
class
MemManage
{
private
:
static
MemManage* _instance_ptr;
public
:
static
MemManage* instance()
{
if
(_instance_ptr==nullptr)
{
_instance_ptr =
new
MemManage();
}
return
_instance_ptr;
}
public
:
MemManage()
{
_threadMutex =
new
QMutex();
_newCount = 0;
_deleteCount = 0;
}
template
<
typename
T>
T* New()
{
ShowOperationMessage<T>(
true
);
return
new
T();
};
template
<
typename
T,
typename
TParam1>
T* New(TParam1 param)
{
ShowOperationMessage<T>(
true
);
return
new
T(param);
};
template
<
typename
T,
typename
TParam1,
typename
TParam2>
T* New(TParam1 param1,TParam2 param2)
{
ShowOperationMessage<T>(
true
);
return
new
T(param1,param2);
};
template
<
typename
T>
void
Delete(T t)
{
if
(t == nullptr)
return
;
ShowOperationMessage<T>(
false
);
delete
t;
};
void
ShowNewDelete(
bool
isShowDetail)
{
int
leftNew = _newCount-_deleteCount;
qDebug()<<
"***********************"
;
qDebug()<<
"total New:"
<<_newCount<<
" Delete:"
<<_deleteCount<<
" leftNew:"
<<leftNew;
if
(isShowDetail)
{
ShowNewDeleteDetail(
false
);
}
}
void
SetShowDetail(
bool
enable)
{
_showDetailMessage = enable;
}
template
<
typename
T>
void
clearAndDelete(QList<T>& list)
{
foreach(T item ,list)
{
// Delete(item);
}
list.clear();
};
private
:
template
<
typename
T>
void
ShowOperationMessage(
bool
isNew)
{
LockRealse lock(_threadMutex);
const
type_info &nInfo =
typeid
(T);
QString className = nInfo.name();
className=TrimClassName(className);
AddCount(className,isNew);
if
(isNew)
{
_newCount++;
}
else
{
_deleteCount++;
}
if
(!_showDetailMessage)
{
return
;
}
if
(isNew)
{
qDebug()<<
"*New"
<<className<<
":"
<<_newCount<<
":"
<<_deleteCount;
}
else
{
qDebug()<<
"Delete"
<<className<<
":"
<<_newCount<<
":"
<<_deleteCount;
}
}
void
AddCount(QString& className,
bool
isNew)
{
QMap<QString,MemObjInfo*>::ConstIterator i = _mapMemObjCount.find(className);
if
(i == _mapMemObjCount.constEnd())
{
MemObjInfo* info =
new
MemObjInfo();
info->ClassName = className;
if
(isNew)
{
info->NewCount++;
}
else
{
info->DeletCount++;
}
_mapMemObjCount.insert(className,info);
}
else
{
MemObjInfo* info = i.value();
if
(isNew)
{
info->NewCount++;
}
else
{
info->DeletCount++;
}
}
}
void
ShowNewDeleteDetail(
bool
isShowAll)
{
QMap<QString,MemObjInfo*>::ConstIterator i = _mapMemObjCount.cbegin();
for
(;i!=_mapMemObjCount.cend();i++)
{
MemObjInfo *info = i.value();
int
leftNew =info->NewCount-info->DeletCount ;
if
(leftNew!=0)
{
qDebug()<<
"*** obj "
<<info->ClassName<<
" New:"
<<info->NewCount
<<
" Delete:"
<<info->DeletCount
<<
" Diff:"
<<leftNew;
}
else
{
if
(isShowAll)
{
qDebug()<<
"obj "
<<info->ClassName<<
" New:"
<<info->NewCount
<<
" Delete:"
<<info->DeletCount
<<
" Diff:"
<<leftNew;
}
}
}
}
QString TrimClassName(QString& className)
{
int
n= className.lastIndexOf(
" *"
);
if
(n<0)
return
className.trimmed();
return
className.mid(0,n).trimmed();
}
private
:
QMutex *_threadMutex;
int
_newCount;
int
_deleteCount;
bool
_showDetailMessage =
false
;
QMap<QString,MemObjInfo*> _mapMemObjCount;
};
#endif // MEMMANAGE_H
|
解决内存泄漏的方法很多。本文介绍了一种行之有效的方法。开发一个新项目前,就需确定如何跟踪定位内存泄漏,发现问题越早解决起来越简单。程序开发是循序渐进的过程,一个功能模块开发完成后,需及早确定是否有内存泄漏。防微杜渐,步步为营,方能产出高质量的产品.
以上就是c++ 防止内存泄漏的妙招的详细内容,更多关于c++ 防止内存泄漏的资料请关注我其它相关文章! 。
原文链接:https://www.cnblogs.com/yuanchenhui/p/memleak.html 。
最后此篇关于c++ 排查内存泄漏的妙招的文章就讲到这里了,如果你想了解更多关于c++ 排查内存泄漏的妙招的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我在具有 2CPU 和 3.75GB 内存 (https://aws.amazon.com/ec2/instance-types/) 的 c3.large Amazon EC2 ubuntu 机器上运
我想通过用户空间中的mmap-ing并将地址发送到内核空间从用户空间写入VGA内存(视频内存,而不是缓冲区),我将使用pfn remap将这些mmap-ed地址映射到vga内存(我将通过 lspci
在 Mathematica 中,如果你想让一个函数记住它的值,它在语法上是很轻松的。例如,这是标准示例 - 斐波那契: fib[1] = 1 fib[2] = 1 fib[n_]:= fib[n] =
我读到动态内存是在运行时在堆上分配的,而静态内存是在编译时在堆栈上分配的,因为编译器知道在编译时必须分配多少内存。 考虑以下代码: int n; cin>>n; int a[n]; 如果仅在运行期间读
我是 Python 的新手,但我之前还不知道这一点。我在 for 循环中有一个基本程序,它从站点请求数据并将其保存到文本文件但是当我检查我的任务管理器时,我发现内存使用量只增加了?长时间运行时,这对我
我正在设计一组数学函数并在 CPU 和 GPU(使用 CUDA)版本中实现它们。 其中一些函数基于查找表。大多数表占用 4KB,其中一些占用更多。基于查找表的函数接受一个输入,选择查找表的一两个条目,
读入一个文件,内存被动态分配给一个字符串,文件内容将被放置在这里。这是在函数内部完成的,字符串作为 char **str 传递。 使用 gdb 我发现在行 **(str+i) = fgetc(aFil
我需要证实一个理论。我正在学习 JSP/Java。 在查看了一个现有的应用程序(我没有写)之后,我注意到一些我认为导致我们的性能问题的东西。或者至少是其中的一部分。 它是这样工作的: 1)用户打开搜索
n我想使用memoization缓存某些昂贵操作的结果,这样就不会一遍又一遍地计算它们。 两个memoise和 R.cache适合我的需要。但是,我发现缓存在调用之间并不可靠。 这是一个演示我看到的问
我目前正在分析一些 javascript shell 代码。这是该脚本中的一行: function having() { memory = memory; setTimeout("F0
我有一种情况,我想一次查询数据库,然后再将整个数据缓存在内存中。 我得到了内存中 Elasticsearch 的建议,我用谷歌搜索了它是什么,以及如何在自己的 spring boot 应用程序中实现它
我正在研究 Project Euler (http://projecteuler.net/problem=14) 的第 14 题。我正在尝试使用内存功能,以便将给定数字的序列长度保存为部分结果。我正在
所以,我一直在做 Java 内存/注意力游戏作业。我还没有达到我想要的程度,它只完成了一半,但我确实让 GUI 大部分工作了......直到我尝试向我的框架添加单选按钮。我认为问题可能是因为我将 JF
我一直在尝试使用 Flask-Cache 的 memoize 功能来仅返回 statusTS() 的缓存结果,除非在另一个请求中满足特定条件,然后删除缓存。 但它并没有被删除,并且 Jinja 模板仍
我对如何使用 & 运算符来减少内存感到非常困惑。 我可以回答下面的问题吗? clase C{ function B(&$a){ $this->a = &$a; $thi
在编写代码时,我遇到了一个有趣的问题。 我有一个 PersonPOJO,其 name 作为其 String 成员之一及其 getter 和 setter class PersonPOJO { priv
在此代码中 public class Base { int length, breadth, height; Base(int l, int b, int h) { l
Definition Structure padding is the process of aligning data members of the structure in accordance
在 JavaScript Ninja 的 secret 中,作者提出了以下方案,用于在没有闭包的情况下内存函数结果。他们通过利用函数是对象这一事实并在函数上定义一个属性来存储过去调用函数的结果来实现这
我正在尝试找出 map 消耗的 RAM 量。所以,我做了以下事情;- Map cr = crPair.collectAsMap(); // 200+ entries System.out.printl
我是一名优秀的程序员,十分优秀!