C++抛出异常会导致内存泄漏
C++ throwing exception causes memory leak
我最近遇到了一个内存泄漏问题。我对这个问题进行了很长时间的故障排除,随后发现抛出异常(我使用自己的异常类)会导致内存泄漏。抛出异常的代码如下:
HINSTANCE lib = LoadLibrary(path.c_str());
if(!lib)
{
DWORD werror = GetLastError();
ostringstream stream;
stream << werror;
string errstring = "Error " + stream.str();
errstring.append(" - " + libraryName);
throw LibraryLoadException(MOD_ERROR_LIB_LOAD, errstring.c_str());
}
结果输出看起来像:
Detected memory leaks!
Dumping objects ->
{351} normal block at 0x0044D208, 32 bytes long.
Data: <Error 126 - note> 45 72 72 6F 72 20 31 32 36 20 2D 20 6E 6F 74 65
{347} normal block at 0x0043BD98, 8 bytes long.
Data: <4 > > 34 F2 3E 00 00 00 00 00
{344} normal block at 0x0043FDE8, 32 bytes long.
Data: <126 > 31 32 36 CD CD CD CD CD CD CD CD CD CD CD CD CD
{302} normal block at 0x004409D8, 8 bytes long.
Data: <4 > > 34 F3 3E 00 00 00 00 00
{301} normal block at 0x0043FAF0, 8 bytes long.
Data: <P > > 50 F3 3E 00 00 00 00 00
Object dump complete.
如visual studio泄漏CrtDbg的输出所示,if块中使用了对象的实际值。不过,包括异常本身(及其所有属性)在内的所有这些对象都是在堆栈上分配的,所以我不可能忘记释放堆上的某些对象。我对此进行了经验测试,泄漏肯定是由if块中的对象引起的(在删除了字符串、DWORD和流等几个对象后,泄漏会减少)。
有人能告诉我我在这里做错了什么吗?
提前感谢
至于要求更详细代码的注释,以下是导致内存泄漏的方法:
void ModuleLoader::load(std::string libraryName, std::string type, void(CALLBACK * receiveData)(Message))
{
path = s2ws(libraryName); // conversion to wide string
HINSTANCE lib = LoadLibrary(path.c_str());
if(!lib)
{
DWORD werror = GetLastError();
ostringstream stream;
stream << werror;
string errstring = "Error " + stream.str();
errstring.append(" - " + libraryName);
throw LibraryLoadException(MOD_ERROR_LIB_LOAD, errstring.c_str());
}
DllModule *module = new DllModule(libraryName, lib);
module->setModType(type);
try
{
startModule(module, receiveData);
moduleMap.insert(std::pair<std::string, DllModule *>(type, module));
}
catch (ProbeCoreException e)
{
delete module;
throw e;
}
}
它是加载动态模块的单例类的方法,定义如下:
class ModuleLoader
{
// Function pointer definitions
typedef void (*StopFuncPointer)();
typedef int (*StartFuncPointer)(void(CALLBACK * receiveData)(Message));
typedef void (*SetDataFunctionPointer)(Message);
private:
std::map<std::string, DllModule *> moduleMap; // map of loaded modules
std::wstring path;
std::wstring s2ws(const std::string &s);
void startModule(DllModule * module, void(CALLBACK * receiveData)(Message));
void stopModule(DllModule * module);
// singleton functions
ModuleLoader() {}; // private constructor
ModuleLoader(ModuleLoader const&);
void operator = (ModuleLoader const&);
public:
void load(std::string libraryName, std::string type, void(CALLBACK * receiveData)(Message));
void unload(std::string libraryType);
void unloadAll();
vector<DllModule> getLoadedModules();
int containsModuleType(string modType);
HINSTANCE getModuleLibraryByType(std::string type);
// singleton getInstance function
static ModuleLoader & getInstance()
{
static ModuleLoader instance;
return instance;
}
};
s2ws方法将普通字符串转换为宽字符串(我发布它只是为了以防万一):
std::wstring ModuleLoader::s2ws(const std::string& s)
{
int len;
int slength = (int)s.length() + 1;
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
std::wstring r(buf);
delete[] buf;
return r;
}
我检查了很多次,抛出异常时释放堆对象应该在应用程序的所有级别上执行。此外,如果我删除DWORD、ostringstream和字符串对象(在堆栈上分配),内存泄漏会减少。。。所以它也必须与这些联系起来。我无法想象删除这部分代码会如何帮助其他地方的堆内存释放:
DWORD werror = GetLastError();
ostringstream stream;
stream << werror;
string errstring = "Error " + stream.str();
errstring.append(" - " + libraryName);
好吧,我设法将泄漏减少到原来5:的两个
Dumping objects ->
{312} normal block at 0x0045FDC8, 8 bytes long.
Data: <( ( > 28 ED 28 00 00 00 00 00
{311} normal block at 0x0045F810, 8 bytes long.
Data: <D ( > 44 ED 28 00 00 00 00 00
Object dump complete.
我使用了_CrtSetBreakAlloc(x)函数,其中x是泄漏的数字(例如,在上述情况下为311或312),并找到了未分配的内存分配在哪里。真的很难相信,但分配确实发生在以下几行:
string errstring = "Error " + stream.str();
and
errstring.append(" - " + libraryName);
我通过在堆上动态分配字符串和流来消除泄漏,然后创建异常并将其存储在临时变量中,随后释放字符串和流变量,最后抛出异常本身:
DWORD werror = GetLastError();
ostringstream *stream = new ostringstream();
*stream << werror;
string *errstring = new string("Error ");
errstring->append(stream->str());
errstring->append(" - ");
errstring->append(libraryName);
ProbeCoreException e = LibraryLoadException(MOD_ERROR_LIB_LOAD,
errstring->c_str());
delete errstring;
delete stream;
throw e;
最后两个分配(再次令人难以置信)发生在将字符串参数传递给"加载"函数本身的过程中:
loader.load("notexisting.dll", "TEST", &callbackFunction);
我正在考虑由于类是单例而发生的泄漏,尽管这里提到了,但该类是根据防泄漏单例规则创建的:
C++Singleton设计模式
似乎唯一的机会是如何摆脱静止的泄漏是传递字符串指针,即使是作为参数,然后显式地解除它们的锁定。。。
- 从构造函数抛出异常时如何克服内存泄漏
- malloc() 可能出现内存泄漏
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 尽管遵循了规则,内存泄漏在哪里
- 为什么调用堆栈数组会导致内存泄漏
- 在简单示例中,Python3 + ctypes 回调会导致内存泄漏
- 使用模板类的自定义列表类型中的内存泄漏
- 为什么以下C++代码中存在内存泄漏?
- OpenCV 我应该使用智能指针来防止内存泄漏吗?
- 我是否生成线程并导致内存泄漏?
- 多线程程序中出现意外的内存泄漏
- 为什么此函数会导致内存泄漏?
- 在 C++ 库中使用cythonized python时内存泄漏
- 需要帮助查找内存泄漏
- 瓦尔格林德的内存泄漏使用新的
- 无法找出我的代码中的内存泄漏
- C++ 结构内部的unordered_map会导致内存泄漏问题吗?
- 可视化 使用 VS Code 查找C++应用程序中的内存泄漏
- Shared_ptr双链接列表内存泄漏
- C++ 在类中使用常量引用文本时 O2 内存泄漏