2013-01-09 17 views
3

저는 tcmalloc을 통합하려고하는 64 비트 Visual Studio 2010 (단일 스레드) C++ Windows 응용 프로그램을 가지고 있으며 동적으로 연결된 DLL을 사용할 때 문제가 발생합니다. tcmalloc을 정적 라이브러리로 연결했습니다. tcmalloc은 응용 프로그램이 공유 DLL 중 하나를 사용하기 시작할 때까지 훌륭하게 작동합니다. 필자는이 솔루션을 64 비트 디버그 애플리케이션으로 만들었습니다. CRT 라이브러리의 C/C++ 디버그 버전 (MSVCP100D.dll 및 MVCR100D.dll)과의 모든 dll 링크누군가 공유 DLL을 사용하는 Windows 64 비트 응용 프로그램에 tcmalloc을 통합 할 수 있습니까?

다음은 실패한 코드의 예입니다. tcmalloc은 모든 메모리 할당에 대해 호출되지만 delete가 호출되면 응용 프로그램이 충돌합니다. 주요 실행 파일에서 함수를 생성하고 거기에 코드를 복사했을 때 똑같은 코드가 제대로 작동하므로 정말 당황 스럽습니다.

이러한 상황에서 tcmalloc을 사용한 경험이있는 사람이라면 언제든지 의견을 보내 주시면 감사하겠습니다. 나에게 수수께끼이다. 그것은 dll의 메모리 모델 문제입니까 (다른 힙은 ??)? 나는 모른다. 그들은 나에게 같은 힙을 사용하고있는 것 같습니다.

이 게시물이 너무 길어서 죄송합니다. 가능한 한 많은 정보를 제공하려고했습니다.

감사합니다.

브루스

업데이트 : 시험 삼아 내가 정적 라이브러리에 충돌 한 공유 DLL을 변경하고 응용 프로그램이 다른 DLL을 사용 할 때까지 모든 것이 괜찮 았는데. 어떤 이유로 든 tcmalloc은 공유 dll을 처리하기 위해 몇 가지 추가 단계가 필요합니다. tcmalloc을 사용하여 메모리 프로파일 링을위한 모든 dll의 정적 라이브러리를 만들 수 있지만, dcm과 tcmalloc을 공유하기 위해 수행해야 할 작업을 알면 정말 좋습니다.

DLL 헤더 파일 메서드 선언 : __declspec (dllexport) static std :: string GetExecutablePath();

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

메모리를 해제 할 때 지금 다른 위치에 충돌 공유 DLL로 tcmalloc을 재건 한 후 :

//.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; 

} 

방법 임시 문자열이 파괴 될 때 호출 .

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 :

그것은 도서관의 내부 상태의 자신의 사본의 얻을 사용하는 정적 각 DLL tcmalloc을 연결하여
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 
} 

답변

1

(힙 포함 및 모든 포인터). 하나의 DLL에서 tcmalloc을 통해 메모리를 할당하고 다른 DLL에서 삭제하려고하면 여러 힙에 액세스하게되므로 작업이 실패합니다.

tcmalloc을 동적 라이브러리로 링크하면 문제가 사라집니다.

+0

감사합니다. 나는 그것을 시도 할 것이다. – Bruce

+0

Captain Oblivious - 동적 DLL로 tcmalloc을 사용하여 응용 프로그램을 재구성했으며 이제 다른 곳에서 충돌합니다 (위의 업데이트 된 코드 참조). free_dbg라는 함수를 호출하여 결국 힙을 검증하는 함수를 호출하고 tcmalloc이 내가 이해하는 유일한 힙이어야하므로 실행 경로를 따라야한다고 생각하지 않습니다. – Bruce

+0

문제는 우리가 우리의 애플리케이션의 디버그 버전을 빌드 할 때 MFC dll의 디버그 버전이 자신의 버전의 new 연산자와 tcmalloc과의 충돌을 일으키는 delete를 가지고 있다는 것입니다. 디버그 버전의 애플리케이션을 빌드 할 때 릴리스 버전의 MFC와 연결하는 방법이 있었으면 좋겠다. – Bruce

1

우리는 마침내 tcmalloc을 Windows의 64 비트 플랫폼에서 공유 DLL로 작동 시켰습니다. Oblivious 선장님의 제안에 감사드립니다! 트릭은 Visual Studio 2010에서 디버그 기호 (How to: Debug a Release Build)를 사용하여 릴리스 버전을 빌드하는 것입니다. tcmalloc은 _free_dbg와 같은 MFC의 CRT 디버그 힙 호출과 충돌합니다.tcmalloc에서 메모리를 할당하고 MFC CRT 힙 디버그 호출에서 할당을 해제했습니다. 릴리스 빌드에서 문제가 사라졌습니다. 우리는 몇 가지 예비 테스트를 수행했으며 tcmalloc은 힙 프로파일 호출 그래프를 생성합니다.

감사합니다.

브루스

+0

실제로'tcmalloc' *은'_free_dbg'를 가로 챌 것입니다. 어설 션은 (차단 된)'_free_dbg'를 호출하기 전에'delete'의 디버그 화신에서 발생합니다 – vladr