由map.insert使用不当引起的内存泄漏
发布日期:2021-06-30 22:17:13 浏览次数:2 分类:技术文章

本文共 6158 字,大约阅读时间需要 20 分钟。

前言

有个写好的cm有内存泄漏,跑了一天,给客户的计算机内存(好像还蛮大的内存)用的差不多了。

当停掉这个cm时,内存一下就正常了(不知道是不是OS给回收了)。
就在找这个内存泄漏问题,bug还没找完。
先发现了一个由map.insert使用不当引起的内存泄漏。
按照c++ reference的说法,同一个key,不同的value, 插入map时。map会更新这个value.
我做的实验,不会更新value.
正确的做法。插入key-value之前,需要find一下key.
如果key不在,选择插入。
如果key存在,可以按照业务逻辑,不插入或更新value.
如果没有将value插入map, 就需要删掉要插入的value(假设value是指针)。
写C程序时,还是要细致点。有些不常用的知识点,如果不太确定,可以先做个实验,再写正式代码。
写好后,运行一些可以想到的测试用例,保证加入的功能模块是正确的(逻辑正确,无内存泄漏,最好性能也好点)。
这样做以后,回头来改bug的概率就小了。等代码堆多了,再回头来修bug, 找bug也要一些时间的。

实验

// @file main.cpp// view date time// date "+DATE: %m/%d/%y%nTIME: %H:%M:%S"// set date time// date -s "2018-3-13 14:25:00"#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
// 不管是否delete, 最后指针都要赋值为空#define SAFE_DELETE(p) \do { \ if (NULL != (p)) { \ delete (p);\ } \ (p)=NULL; \} while (0);class class_my_Key {public: uint ip; ushort port; class_my_Key() { } class_my_Key(uint ip, ushort port) { this->init(ip, port); } void init(uint ip, ushort port) { this->ip = ip; this->port = port; } bool operator <(const class_my_Key &r) const { if (this->ip < r.ip) { return true; } else if (this->ip > r.ip) { return false; } //ip == ip if (this->port < r.port) { return true; } else if (this->port > r.port) { return false; } //port == port return false; }};class class_my_session {public: uint ip; ushort port; std::string str_name;public: class_my_session() { this->ip = 0; this->port = 0; str_name="unknown"; } virtual ~class_my_session() { } void copy(class_my_session* psrc) { this->ip = psrc->ip; this->port = psrc->port; this->str_name = psrc->str_name.c_str(); } void show_info() { printf("name = [%s] : ip = [%d] : port = [%d]\n", str_name.c_str(), ip, port); }};std::map
g_ses_map;typedef std::map
::iterator Ses_Map_It;typedef std::pair
Ses_Map_Pair;typedef std::pair
Ses_Map_Pair_rc;void init();void uninit();class_my_session* gen_ses1();class_my_session* gen_ses2();class_my_session* gen_ses3();void insert_to_map_err(class_my_session*& ses);void insert_to_map_ok(class_my_session*& ses);void show_map();void free_map();void fn_map_usage_err();void fn_map_usage_ok();int fn_test();int main(int argc, char** argv){ init(); fn_test(); uninit(); return EXIT_SUCCESS;}int fn_test(){ fn_map_usage_err(); fn_map_usage_ok();}void init(){}void uninit(){}class_my_session* gen_ses1(){ class_my_session* ses1 = new class_my_session(); ses1->ip = 11111; ses1->port = 111; ses1->str_name = "ses1"; return ses1;}class_my_session* gen_ses2(){ class_my_session* ses1 = new class_my_session(); ses1->ip = 11111; ses1->port = 111; ses1->str_name = "ses2"; return ses1;}class_my_session* gen_ses3(){ class_my_session* ses1 = new class_my_session(); ses1->ip = 11111; ses1->port = 111; ses1->str_name = "ses3"; return ses1;}void show_map() { Ses_Map_It it = g_ses_map.end(); for (it = g_ses_map.begin(); it != g_ses_map.end(); it++) { if (NULL != it->second) { it->second->show_info(); } }}void insert_to_map_err(class_my_session*& ses){ Ses_Map_It it = g_ses_map.end(); Ses_Map_Pair_rc rc_pair; if (NULL != ses) { class_my_Key key(ses->ip, ses->port); it = g_ses_map.find(key); if (it != g_ses_map.end()) { printf("find key\n"); } else { printf("not find key\n"); } rc_pair = g_ses_map.insert(Ses_Map_Pair(key, ses)); printf("insert %s, status = %s, ses_map.size() = %d\n", (rc_pair.first != g_ses_map.end()) ? "true" : "false", rc_pair.second ? "was insert" : "was update", (int)g_ses_map.size()); show_map(); printf("\n"); }}void insert_to_map_ok(class_my_session*& ses){ Ses_Map_It it = g_ses_map.end(); Ses_Map_Pair_rc rc_pair; if (NULL != ses) { class_my_Key key(ses->ip, ses->port); it = g_ses_map.find(key); if (it != g_ses_map.end()) { printf("find key, update it\n"); it->second->copy(ses); SAFE_DELETE(ses); } else { printf("not find key\n"); rc_pair = g_ses_map.insert(Ses_Map_Pair(key, ses)); printf("insert %s, status = %s, ses_map.size() = %d\n", (rc_pair.first != g_ses_map.end()) ? "true" : "false", rc_pair.second ? "was insert" : "was update", (int)g_ses_map.size()); } show_map(); printf("\n"); }}void free_map() { Ses_Map_It it = g_ses_map.end(); printf("free map, ses_map.size() = %d\n", (int)g_ses_map.size()); for (it = g_ses_map.begin(); it != g_ses_map.end(); it++) { if (NULL != it->second) { it->second->show_info(); } SAFE_DELETE(it->second); } g_ses_map.clear();}void fn_map_usage_err() { class_my_session* ses = NULL; printf("\n\n"); printf(">> fn_map_usage_err\n"); // insert key1 and ses1 ses = gen_ses1(); insert_to_map_err(ses); // insert key2 and ses2 ses = gen_ses2(); insert_to_map_err(ses); // insert key3 and ses3 ses = gen_ses3(); insert_to_map_err(ses); // free map free_map(); /** run result >> fn_map_usage_err not find key insert true, status = was insert, ses_map.size() = 1 name = [ses1] : ip = [11111] : port = [111] find key insert true, status = was update, ses_map.size() = 1 name = [ses1] : ip = [11111] : port = [111] find key insert true, status = was update, ses_map.size() = 1 name = [ses1] : ip = [11111] : port = [111] free map, ses_map.size() = 1 name = [ses1] : ip = [11111] : port = [111] */ /** note 按照c++ reference的说法,如果key相同,会更新value 错误的map用法,引起了内存泄漏, 插入同一个key, 如果key存在, 会更新value. 当value是一个new出来的指针时,原始的指针被替换成新指针了,原始的指针就没人管了 map free时,也释放不到原始指针,引起内存泄漏 从实验结果看, 就是插入了3个指针,只释放了一个指针 我的实验[Red Hat Enterprise Linux Server release 5.4 (Tikanga)], 插入map失败,不替换指针. 如果不处理插入前的指针,那也是插入一回, 就丢了一个指针 假设key用的ip是服务器ip, port是服务的端口号. 不管是否在同一台计算机上用多个客户端去连服务,ip和port都是相同的, 即key相同 */}void fn_map_usage_ok() { class_my_session* ses = NULL; printf("\n\n"); printf(">> fn_map_usage_ok\n"); // insert key1 and ses1 ses = gen_ses1(); insert_to_map_ok(ses); // insert key2 and ses2 ses = gen_ses2(); insert_to_map_ok(ses); // insert key3 and ses3 ses = gen_ses3(); insert_to_map_ok(ses); // free map free_map(); /** run result >> fn_map_usage_ok not find key insert true, status = was insert, ses_map.size() = 1 name = [ses1] : ip = [11111] : port = [111] find key, update it name = [ses2] : ip = [11111] : port = [111] find key, update it name = [ses3] : ip = [11111] : port = [111] free map, ses_map.size() = 1 name = [ses3] : ip = [11111] : port = [111] */}

转载地址:https://lostspeed.blog.csdn.net/article/details/79600340 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:用屏蔽法找bug的总结
下一篇:new指针后,地址相同

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月27日 01时55分23秒