c – 有没有人能够在使用共享DLL的Windows 64位应用程序上集成tcmalloc?

我有一个64位Visual Studio 2010(单线程)C
Windows应用程序,我试图集成tcmalloc和我在使用任何动态链接的DLL时遇到问题.我将tcmalloc链接为静态库. tcmalloc很有效,直到应用程序开始使用我们的共享dll之一.我将解决方案构建为64位DEBUG应用程序.所有dll都与CRT库的C/C++调试版本(MSVCP100D.dll和MVCR100D.dll)相关联.

下面是失败的代码示例.为所有内存分配调用tcmalloc,但是当调用delete时,应用程序崩溃.这对我来说真的很令人费解,因为当我在主可执行文件中创建一个函数并在那里复制代码时,完全相同的代码工作正常.

如果有人在这种情况下使用tcmalloc有任何经验,我将非常感谢您的反馈.这对我来说是一个谜.这是dll的内存模型问题(不同的堆??)?我不知道.在我看来,他们使用相同的堆.

对不起,如果这篇文章太长了.我试图提供尽可能多的信息.

谢谢.

布鲁斯

更新:作为测试,我将崩溃的共享dll更改为静态库,一切正常,直到应用程序使用不同的dll.因此无论出于何种原因,tcmalloc需要一些额外的步骤来处理共享的dll.我可以使用tcmalloc制作所有dll的静态库以进行内存分析,但知道使用共享还需要做什么才真的很好
dll与tcmalloc.

DLL头文件方法声明:
__declspec(dllexport)static std :: string GetExecutablePath();

//.cpp实现

string Parameters::GetExecutablePath()

    string  execPathStr;
    char exeFilePath[ MAX_PATH +1];
    if ( GetModuleFileName( NULL, exeFilePath, MAX_PATH ) )
    {
        //The line of code below is where the app crashes.
        //It calls operator new in crt/src/new.cpp. I verified the call to malloc
        //is forwarded to tcmalloc. 
        *execPathStr = string(exeFilePath);* //creates and deletes a temporary and then crashes

        long dir_pos = execPathStr.rfind( FT_DIR_SLASH ) ;
        execPathStr = execPathStr.substr( 0, dir_pos+1 );
    }

    return execPathStr;

}

临时字符串销毁时调用的方法:

~_String_val()
{   
    // destroy the object
    typename _Alloc::template rebind<_Container_proxy>::other _Alproxy(_Alval);
    this->_Orphan_all();
    _Dest_val(_Alproxy, this->_Myproxy);
    **_Alproxy.deallocate(this->_Myproxy, 1);**
    this->_Myproxy = 0;
}


void deallocate(pointer _Ptr, size_type)
{   
    // deallocate object at _Ptr, ignore size
    **::operator delete(_Ptr);**
}

This is where it crashes. the pHead->nBlockUse is 0. 
crt/dbgdel.cpp:

void operator delete(
        void *pUserData
        )
{
    //code omitted for brevity
    /* verify block type */
    **_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));** //crashes here
}

在将tcmalloc重建为共享DLL后,它在尝试释放内存时会在不同的位置崩溃.

afxmem.cpp:

void __cdecl operator delete(void* p)
{
#if !defined(_AFX_NO_DEBUG_CRT) && defined(_DEBUG)
        **_free_dbg(p, _NORMAL_BLOCK);** <-------- this function gets called 
#else
        free(p);
#endif
}

dbgheap.c:

extern "C" _CRTIMP void __cdecl _free_dbg(
        void * pUserData,
        int nBlockUse
        )
{
 _mlock(_HEAP_LOCK);

        __try {
            /* allocate the block
             */
            **_free_dbg_nolock(pUserData, nBlockUse);**
        }
   __finally {
            /* unlock the heap
             */
            _munlock(_HEAP_LOCK);
        }
}



extern "C" void __cdecl _free_dbg_nolock(
        void * pUserData,
        int nBlockUse
        )
{
    //code omitted for brevity

    /*
    * If this ASSERT fails, a bad pointer has been passed in. It may be
    * totally bogus, or it may have been allocated from another heap.
    * The pointer MUST come from the 'local' heap.
    */
    **_ASSERTE(_CrtIsValidHeapPointer(pUserData));** <-------- crashes here
}

最佳答案 通过静态链接tcmalloc,每个使用它的DLL都会获得它自己的库内部状态副本(包括堆和所有指针).如果您通过tcmalloc从一个DLL分配内存并尝试从另一个DLL中删除操作将失败,因为您最终访问多个堆.

将tcmalloc链接为动态库,您的问题应该消失.

点赞