title: Has anyone been able to integrate tcmalloc on a Windows 64 bit application that uses shared DLL's?
body: <p>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). </p>
  
  <p>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.</p>
  
  <p>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. </p>
  
  <p>Sorry if this post is too long. I was trying to give as much info as possible.</p>
  
  <p>Thank you.</p>
  
  <p>Bruce</p>
  
  <p>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.</p>
  
  <p>DLL Header file method declaration:
  __declspec(dllexport) static std::string GetExecutablePath();</p>
  
  <p>//.cpp implementation</p>
  
  <pre><code>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;
  
  }
  </code></pre>
  
  <p>Methods called when temporary string destroyed:</p>
  
  <pre><code>~_String_val()
  {   
      // destroy the object
      typename _Alloc::template rebind&lt;_Container_proxy&gt;::other _Alproxy(_Alval);
      this-&gt;_Orphan_all();
      _Dest_val(_Alproxy, this-&gt;_Myproxy);
      **_Alproxy.deallocate(this-&gt;_Myproxy, 1);**
      this-&gt;_Myproxy = 0;
  }
  
  
  void deallocate(pointer _Ptr, size_type)
  {   
      // deallocate object at _Ptr, ignore size
      **::operator delete(_Ptr);**
  }
  
  This is where it crashes. the pHead-&gt;nBlockUse is 0. 
  crt/dbgdel.cpp:
  
  void operator delete(
          void *pUserData
          )
  {
      //code omitted for brevity
      /* verify block type */
      **_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead-&gt;nBlockUse));** //crashes here
  }
  </code></pre>
  
  <p>After rebuilding tcmalloc as a shared DLL it now crashes in a different place when trying to free the memory. </p>
  
  <p>afxmem.cpp:</p>
  
  <pre><code>void __cdecl operator delete(void* p)
  {
  #if !defined(_AFX_NO_DEBUG_CRT) &amp;&amp; defined(_DEBUG)
          **_free_dbg(p, _NORMAL_BLOCK);** &lt;-------- this function gets called 
  #else
          free(p);
  #endif
  }
  </code></pre>
  
  <p>dbgheap.c:</p>
  
  <pre><code>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));** &lt;-------- crashes here
  }
  </code></pre>