博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
由map.insert使用不当引起的内存泄漏
阅读量:1992 次
发布时间:2019-04-27

本文共 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] */}

转载地址:http://zfmvf.baihongyu.com/

你可能感兴趣的文章
搜索中的TSA(树搜索算法) & GSA(图搜索算法) & UCS(代价一致) & CSP(约束满足问题)
查看>>
位图索引Bitmap indexes
查看>>
YOLO算法(二)—— Yolov2 & yolo9000
查看>>
Python的__future__模块
查看>>
Paper reading —— Semantic Stereo Matching with Pyramid Cost Volumes(SSPCV-Net)
查看>>
计算机视觉中的cost-volume的概念具体指什么(代价体积)
查看>>
Paper reading——Pyramid Stereo Matching Network(PSM-Net)
查看>>
启发函数heuristic 与 A*
查看>>
Image Pyramid(图像金字塔)
查看>>
Oracle 作业记录
查看>>
putty连接AWS配置(multimedia project)
查看>>
Hourglass Network 沙漏网络 (pose estimation姿态估计)
查看>>
OpenCV实战(二)——答题卡识别判卷
查看>>
目标检测神经网络的发展历程(52 个目标检测模型)
查看>>
Boundary loss 损失函数
查看>>
神经网络调参实战(一)—— 训练更多次数 & tensorboard & finetune
查看>>
tensorflow使用tensorboard进行可视化
查看>>
神经网络调参实战(二)—— activation & initializer & optimizer
查看>>
凸优化 convex optimization
查看>>
数据库索引 & 为什么要对数据库建立索引 / 数据库建立索引为什么会加快查询速度
查看>>