Кто-нибудь смог интегрировать tcmalloc в Windows 64-разрядное приложение, которое использует общие библиотеки DLL?

У меня 64-битное приложение Visual Studio 2010 (однопоточное) C ++ Windows, которое я пытаюсь интегрировать с tcmalloc, и у меня возникают проблемы при использовании любой из наших динамически связанных библиотек dll. Я связал tcmalloc как статическую библиотеку. tcmalloc отлично работает, пока приложение не начнет использовать одну из наших общих dll. Я построил решение как 64-разрядное приложение DEBUG. Все ссылки dll с отладочными версиями библиотек CRT (MSVCP100D.dll и MVCR100D.dll) на C/C ++.

Ниже приведен пример кода, который терпит неудачу. tcmalloc вызывается для всех распределений памяти, но когда удаление называется сбоем приложения. Это действительно озадачивает меня, поскольку тот же самый код отлично работает, когда я создал функцию в основном исполняемом файле и скопировал там код.

Если у кого-то есть опыт использования tcmalloc в такой ситуации, я был бы признателен за ваши отзывы. Для меня это загадка. Это проблема модели памяти с dll (разные кучи?)? Я не знаю. Мне кажется, что они используют ту же кучу.

Извините, если этот пост слишком длинный. Я пытался дать как можно больше информации.

Спасибо.

Брюс

Обновление. В качестве теста я сменил общую dll, где он врезался в статическую библиотеку, и все работало нормально, пока приложение не использовало другую dll. Поэтому по любой причине tcmalloc требует некоторых дополнительных шагов для обработки общих dll. Я могу сделать все статические библиотеки DLL для профилирования памяти с помощью tcmalloc, но было бы неплохо узнать, что еще нужно сделать, чтобы использовать общие 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
}
4
nl ja de

2 ответы

Путем связывания tcmalloc статически каждая DLL, которая его использует, получает свою собственную копию внутреннего состояния библиотеки (включая кучу и все указатели). Если вы выделяете память через tcmalloc из одной DLL и пытаетесь удалить ее с другой, операция завершится неудачно, потому что вы получите доступ к нескольким кучам.

Свяжите tcmalloc как динамическую библиотеку, и ваша проблема исчезнет.

1
добавлено
AFAIK MFC автоматически не использует поставляемые new и delete операторы. После включения stdafx.h добавьте строку #undef new
добавлено автор Captain Obvlious, источник
Благодарю. Я попробую.
добавлено автор Bruce, источник
Captain Oblivious - я перестроил приложение с помощью tcmalloc в качестве динамической DLL, и теперь он сбой в другом месте (см. Обновленный код выше). Он вызывает функцию, называемую free_dbg, которая в конечном итоге вызывает функцию для проверки кучи, и я не думаю, что она должна следовать этому пути выполнения, поскольку tcmalloc должен быть единственной кучей из того, что я понимаю.
добавлено автор Bruce, источник
Проблема в том, что при создании отладочной версии нашего приложения отладочная версия библиотеки MFC имеет свою собственную версию оператора new и delete, которая вызывает конфликты с tcmalloc. Хотелось бы связать какую-то версию MFC с выпуском, когда мы создаем отладочную версию нашего приложения.
добавлено автор Bruce, источник
Я попробовал это, но он все еще приносит все MFC «_dbg» призывы к malloc и бесплатно при создании решения DEBUG. По-видимому, _DEBUG «Определяется при компиляции с/LDd,/MDd и/MTd». , Если я создаю версию выпуска с информацией об отладке в Visual Studio, tcmalloc не сбой и не выполняет профилирование памяти, но ни один из файлов профилирования памяти не создается. Похоже, что для этого нужно изменить сценарий 6K perl. Любая идея, откуда можно получить имена функций из адресов в сборке релизов? Сохраняются ли они в .pdb? Я считаю, что они хранятся иначе, чем отладочные сборки.
добавлено автор Bruce, источник

Наконец, мы получили tcmalloc, работающий на 64-битной платформе Windows с общими dll. Спасибо капитану Обливию за его предложения! Хитрость заключалась в том, чтобы создать версию Release в Visual Studio 2010 с помощью отладочных символов, как указано в этой статье: Как отладить сборку выпусков . tcmalloc имеет конфликты с вызовами отладки CRT в MFC, такими как: _free_dbg. Мы выделяли память из tcmalloc и освобождались от вызовов отладки MFC CRT. В выпуске сборки эта проблема исчезла. Мы провели предварительное тестирование, а tcmalloc генерирует график вызовов профиля кучи.

Благодарю.

Брюс

1
добавлено
Фактически tcmalloc выполняет перехват _free_dbg , это утверждение происходит в инкабации отладки delete до вызова (перехваченного) _free_dbg
добавлено автор vladr, источник
pro.cxx
pro.cxx
3 049 участник(ов)

C/C++ chat 0. Простые вопросы, лабы и о IDE — в чат новичков @supapro 1. Не хамим, не переходим на личности, не вбрасываем утверждения без доказательств 2. No Ads, offtop, flood Объявления о вакансиях и евенты - в лс @AlexFails https://t.me/ProCxx/259155

supapro.cxx
supapro.cxx
1 925 участник(ов)

Чат для тех, кто немного знает C++, простые вопросы по реализации, синтаксису и ide – сюда, а для другого есть: /Главный чат по серьезным вопросам — @ProCxx /Чат по обсуждению всего — @fludpac

C++ Russia
C++ Russia
384 участник(ов)

Сообщество разработчиков C++ в Telegram.

cxx.Дискуссионная
cxx.Дискуссионная
298 участник(ов)

это не двач, общайтесь вежливо; разговор на почти любые темы; Не согласны с баном? В лс @AlexFails, @ivario

C++ для маленьких и тупых
C++ для маленьких и тупых
105 участник(ов)

Лоу левел (по среднему IQ участников) чатик ExtremeCode @extremecode Флудилка @extremecode_rest