内存泄漏的 STL 替代方案
STL alternative for memory leak
我是C++编码和STL库使用的新手。我对在我正在开发的C++程序中使用 STL 库非常感兴趣。但是最近我尝试使用视觉泄漏检测器,发现许多泄漏,特别是我使用STL库和new
操作员的地方。
由于它是一个运行时应用程序,我还发现当我连续运行代码 4-5 天时,CPU 内存不断增加。在一些论坛和其他笔记中学习,我明白我需要删除/擦除std::map
、std::unordered_map
、std:set
内的内容,然后再调用其相应的clear
。 我的问题是,如果我在析构函数调用上执行所有永远不会调用的操作(因为我的程序员永远不会停止),每次访问 STL 库时都会创建内存泄漏吗?
有没有其他选择?
示例:common.h
struct stTagElem_t {
uint32_t m_unOffset;
uint32_t m_unArraySize;
string m_acTagName;
string m_acTagValue;
string m_acDataType;
} ;
typedef std::unordered_map<uint8_t, stTagElem_t> tagsList_t;
struct stMappingElem_t {
uint16_t m_unMemSize;
tagsList_t m_stTagsList;
string m_acEventName;
string m_acMapTypeName;
} ;
typedef std::unordered_map<uint32_t, stMappingElem_t> eventDataMap_t;
dataMapManager.cpp//声明为全局列表,因为 dataMapManager.cpp 具有所有静态函数
eventDataMap_t sm_eventDataMapList;
因此,当我使用视觉检漏仪时,它说以下内容:
---------- Block 596 at 0x00DE8DB8: 120 bytes ----------
Leak Hash: 0xB26C3A34, Count: 1, Total 120 bytes
Call Stack (TID 11580):
c:program files (x86)microsoft visual studio 14.0vcincludexmemory0 (977): example.exe!std::_Wrap_alloc<std::allocator<std::_List_node<std::pair<unsigned __int64 const ,stMappingElem_t>,void *> > >::allocate()
c:program files (x86)microsoft visual studio 14.0vcincludelist (730): example.exe!std::_List_alloc<std::_List_base_types<std::pair<unsigned __int64 const ,stMappingElem_t>,std::allocator<std::pair<unsigned __int64 const ,stMappingElem_t> > > >::_Buynode0() + 0x11 bytes
c:program files (x86)microsoft visual studio 14.0vcincludelist (716): example.exe!std::_List_alloc<std::_List_base_types<std::pair<unsigned __int64 const ,stMappingElem_t>,std::allocator<std::pair<unsigned __int64 const ,stMappingElem_t> > > >::_Buyheadnode()
c:program files (x86)microsoft visual studio 14.0vcincludelist (649): example.exe!std::_List_alloc<std::_List_base_types<std::pair<unsigned __int64 const ,stMappingElem_t>,std::allocator<std::pair<unsigned __int64 const ,stMappingElem_t> > > >::_List_alloc<std::_List_base_types<std::pair<unsigned __int64 const ,stMappingElem_t>,std::al() + 0x8 bytes
c:program files (x86)microsoft visual studio 14.0vcincludelist (826): example.exe!std::_List_buy<std::pair<unsigned __int64 const ,stMappingElem_t>,std::allocator<std::pair<unsigned __int64 const ,stMappingElem_t> > >::_List_buy<std::pair<unsigned __int64 const ,stMappingElem_t>,std::allocator<std::pair<unsigned __int64 const ,stMappin()
c:program files (x86)microsoft visual studio 14.0vcincludelist (899): example.exe!std::list<std::pair<unsigned __int64 const ,stMappingElem_t>,std::allocator<std::pair<unsigned __int64 const ,stMappingElem_t> > >::list<std::pair<unsigned __int64 const ,stMappingElem_t>,std::allocator<std::pair<unsigned __int64 const ,stMappingElem_t> >()
c:program files (x86)microsoft visual studio 14.0vcincludexhash (197): example.exe!std::_Hash<std::_Umap_traits<unsigned __int64,stMappingElem_t,std::_Uhash_compare<unsigned __int64,std::hash<unsigned __int64>,std::equal_to<unsigned __int64> >,std::allocator<std::pair<unsigned __int64 const ,stMappingElem_t> >,0> >::_Hash<std::_Umap_tra() + 0xF bytes
c:program files (x86)microsoft visual studio 14.0vcincludeunordered_map (119): example.exe!std::unordered_map<unsigned __int64,stMappingElem_t,std::hash<unsigned __int64>,std::equal_to<unsigned __int64>,std::allocator<std::pair<unsigned __int64 const ,stMappingElem_t> > >::unordered_map<unsigned __int64,stMappingElem_t,std::hash<unsigned __int6()
g:myworksrcdatamapmanager.cpp (15): example.exe!`dynamic initializer for 'sm_eventDataMapList''() + 0xD bytes
d:rs1minkernelcrtsucrtsrcappcrtstartupinitterm.cpp (22): ucrtbased.dll!_initterm()
f:ddvctoolscrtvcstartupsrcstartupexe_common.inl (221): example.exe!__scrt_common_main_seh() + 0xF bytes
f:ddvctoolscrtvcstartupsrcstartupexe_common.inl (296): example.exe!__scrt_common_main()
f:ddvctoolscrtvcstartupsrcstartupexe_main.cpp (17): example.exe!mainCRTStartup()
KERNEL32.DLL!BaseThreadInitThunk() + 0x24 bytes
ntdll.dll!__RtlUserThreadStart() + 0x2F bytes
ntdll.dll!_RtlUserThreadStart() + 0x1B bytes
Data:
38 09 E6 00 F0 98 E8 00 CD CD CD CD CD CD CD CD 8....... ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD CD CD CD CD ........ ........
更多地图: common.h
using namespace std;
#ifdef USE_64BIT
typedef uint64_t ID;
#else
typedef uint32_t ID;
#endif
typedef ID EVENT_UID;
struct stEventParams_t {
EVENT_UID m_unEventID;
uint8_t *m_ptrMemAddr;
size_t m_dataSize;
} ;
struct stTagElem_t {
uint32_t m_unOffset;
uint32_t m_unArraySize;
string m_acTagName;
string m_acTagValue;
string m_acDataType;
} ;
typedef std::unordered_map<uint8_t, stTagElem_t> tagsList_t;
struct stMappingElem_t {
uint16_t m_unMemSize;
tagsList_t m_stTagsList;
string m_acEventName;
string m_acMapTypeName;
} ;
typedef std::unordered_map<EVENT_UID, stMappingElem_t> eventDataMap_t;
struct stAppBlocInfo_t {
string m_acAppBlocName;
string m_acInstanceName;
string m_acDataMap_r_SPError;
string m_acTypeName;
} ;
typedef std::unordered_map<string, string> instanceTypeList_t;
typedef struct {
stAppBlocInfo_t m_acServiceProvider;
instanceTypeList_t m_acParamsList;
} stSP_Params_t;
typedef std::unordered_map<string, stSP_Params_t> serviceProvider_t;
struct stServiceParams_t {
bool m_bIsItOutput;
uint8_t m_unIdxToEvtClient;
EVENT_UID m_unEventID;
string m_acInstanceName;
string m_acTypeName;
instanceTypeList_t m_acParamsList;
} ;
typedef std::unordered_map<ID, stServiceParams_t> serviceParams_t;
struct stStatusElem_t {
bool m_bErrorPresent;
std::string m_acSPError;
instanceTypeList_t m_ServiceStatus;
};
typedef std::unordered_map<CSI_base *, stSP_Params_t > spInstanceList_t;
typedef CSI_base* (*CREATE_SI)(stSP_Params_t, eventDataMap_t, serviceParams_t);
typedef std::map<std::string, HINSTANCE> extnSiObjList_t;
struct AppBloc_Elements {
APPBLOCNAME m_acAppBlocName;
CFBNwExecutor *ptrFbnExec;
};
typedef std::map<APPLET_ID, AppBloc_Elements> AppBlocElemList;
typedef std::map<APPBLOCNAME, APPLET_ID> AppBlocsList;
我的整个应用程序由 50+ cpp 文件组成,我在大多数用例中使用标准 STL 库。
您的问题"每次访问 STL 库时都会产生内存泄漏吗?"的回答是否定的。标准库容器确实会根据需要为其操作分配内存,但您必须非常努力地使它们实际上泄漏自己的内存。您提供的 VLD 输出显示按unordered_map分配的内存;它不会泄露,该地图使用它来存储您的数据。如果清除地图,此内存将被释放。
内存使用量增加的原因有两种可能性。首先,您可能会无限期地将越来越多的数据推送到某个容器中。例如,您可能正在创建新事件并将其放入sm_eventDataMapList
而不删除旧事件。在这种情况下,内存必须增加,无论是标准容器还是手动滚动结构。这在VLD中很容易发现,因为随着时间的推移,它会在某些特定位置显示越来越多的分配。这不是容器中的泄漏,这是代码中的错误。
第二种可能性,可能就是发生在您身上 - 是您正在泄漏new
分配的内存。您有责任删除分配的所有对象,new
是否不再使用它们。容器不会自动执行此操作。智能指针可以帮助您完成此任务,但我建议您仔细查看您使用new
的所有位置,并考虑是否真的需要以这种方式分配对象。通常,您可以以不同的方式做事,并获得更简单、更安全的代码。
例如,在这种情况下:unordered_map<CSI_base *, stSP_Params_t >
- 使用指向对象的指针作为键。从地图中删除该元素后,您是否delete
或以其他方式处置该对象?
再比如:
struct stEventParams_t {
EVENT_UID m_unEventID;
uint8_t *m_ptrMemAddr;
size_t m_dataSize;
} ;
我将假设这个结构拥有m_ptrMemAddr
指向的内存,m_dataSize
是该内存块的大小。在这种情况下,您需要记住每次删除实例时都要delete[]
此内存stEventParams_t
这很容易忘记。
更好的方法 - 使结构删除拥有的资源:
struct stEventParams_t {
~stEventParams_t() {delete[] m_ptrMemAddr;}
EVENT_UID m_unEventID;
uint8_t *m_ptrMemAddr;
size_t m_dataSize;
} ;
更好的是 - 使用智能指针:
struct stEventParams_t {
EVENT_UID m_unEventID;
std::unique_ptr<uint8_t[]> m_ptrMemAddr;
size_t m_dataSize;
} ;
甚至更好 - 使用适当的标准容器(不会泄漏内存,也不需要单独的size
,因为容器知道其长度):
struct stEventParams_t {
EVENT_UID m_unEventID;
std::vector<uint8_t> m_data;
} ;
- 运行同一解决方案的另一个项目的项目
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么这个运算符<重载函数对 STL 算法不可见?
- Project Euler问题4的错误解决方案
- 在C应用程序中运行C++(带有STL)函数
- 使用2个键的cpp-stl::优先级队列排序不正确
- 计算每个节点的树高,帮助我解释这个代码解决方案
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- 在STL容器中使用模板类
- visual c++,如何获取解决方案目录中的代码
- 用C++中的CPerson(类)类型的对象初始化STL矢量
- 将stl字符串缩小到小于15个字符的容量
- 在为LINUX创建共享库时,如何避免STL的私有/弱副本
- 检查函数返回类型是否与STL容器类型值相同
- 使用STL对用户输入数组进行排序的错误有什么解决方案吗?
- 使用 stl 排列 std::vector 元素的最短解决方案
- 内存泄漏的 STL 替代方案
- 如何更好地使用 STL 和函子来获取滑动窗口最小值的解决方案
- 什么是STL容器的纯C替代方案
- STL std::map 的更快替代方案