Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Has anyone been able to integrate tcmalloc on a Windows 64 bit application that uses shared DLL's?

I have a 64 bit Visual Studio 2010 (single threaded) C++ Windows application that I am trying to integrate tcmalloc with and I am running into problems when using any of our dynamically linked dll's . I linked tcmalloc as a static library. tcmalloc works great until the application starts using one of our shared dll's . I built the solution as a 64 bit DEBUG application. All of the dll's link with the C/C++ debug versions of CRT libraries (MSVCP100D.dll and MVCR100D.dll).

Below is an example of the code that fails. tcmalloc gets called for all of the memory allocations but when delete is called the application crashes. It is really puzzling to me as the exact same code works fine when I created a function in the main executable and copied the code there.

If anyone has any experience with using tcmalloc in this type of situation I would appreciate your feedback. It is a mystery to me. Is it a memory model issue with the dll's (different heaps ?? ) ? I don't know. It seems to me they are using the same heap.

Sorry if this post is too long. I was trying to give as much info as possible.

Thank you.

Bruce

Update: As a test I changed the shared dll where it was crashing to a static library and everything worked fine until the application used a different dll. So for whatever reason tcmalloc requires some additional steps to handle shared dll's. I can make all of our dll's static libs for memory profiling with tcmalloc but it would really be nice to know what else needs to be done to use shared dll's with tcmalloc.

DLL Header file method declaration: __declspec(dllexport) static std::string GetExecutablePath();

//.cpp implementation

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;

}

Methods called when temporary string destroyed:

~_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
}

After rebuilding tcmalloc as a shared DLL it now crashes in a different place when trying to free the memory.

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
}
like image 404
Bruce Avatar asked Oct 22 '22 20:10

Bruce


1 Answers

We finally got tcmalloc working on Windows 64 bit platform with shared dll's. Thanks to Captain Oblivious for his suggestions ! The trick was to build a release version in Visual Studio 2010 with debug symbols as stated in this article: How to: Debug a Release Build . tcmalloc has conflicts with CRT debug heap calls in MFC such as: _free_dbg. We were allocating memory from tcmalloc and deallocating from MFC CRT heap debug calls. In a release build that problem went away. We did some preliminary testing and tcmalloc is generating the heap profile call graph.

Thanks.

Bruce

like image 50
Bruce Avatar answered Oct 27 '22 12:10

Bruce