[英]Unexpected Behaviour from tcmalloc
我在一個大型項目中使用tcmalloc已有幾個月了,到目前為止我必須說我很高興,最重要的是它的HeapProfiling功能允許跟蹤內存泄漏並刪除它們。
在過去的幾周里,雖然我們的應用程序中遇到了隨機崩潰,但我們無法找到隨機崩潰的來源。 在一個非常特殊的情況下,當應用程序崩潰時,我們發現自己的應用程序線程之一的堆棧已完全損壞。 相反,我發現線程被卡在tcmalloc :: PageHeap :: AllocLarge()中,但由於我沒有連接tcmalloc的調試符號,我無法理解問題是什么。
經過近一周的調查,今天我嘗試了最簡單的事情:從連接中刪除tcmalloc以避免使用它,只是為了看看發生了什么。 嗯......我終於找到了問題所在,而且有問題的代碼看起來非常像這樣:
void AllocatingFunction()
{
Object object_on_stack;
ProcessObject(&object_on_stack);
}
void ProcessObject(Object* object)
{
...
// Do Whatever
...
delete object;
}
使用libc,應用程序仍然崩潰,但我終於看到我在堆棧上分配的對象上調用了delete。
我仍然無法弄清楚的是為什么tcmalloc保持應用程序運行而不管這種非常危險(如果不是完全錯誤的)對象釋放,以及當AllocatingFunction結束時object_on_stack超出范圍時的雙重釋放。 事實是,可以反復調用違規代碼而不暗示潛在的憎惡。
我知道,如果使用不當,內存釋放是那些“未定義的行為”之一,但令我驚訝的是“標准”libc和tcmalloc之間存在這種不同的行為。
有沒有人對tcmalloc保持應用程序運行的原因有一些洞察力的解釋?
提前致謝 :)
祝你今天愉快
對象釋放非常危險(如果不是完全錯誤的話)
好吧,我在這里不同意,這是完全錯誤的,因為你調用UB,任何事情都可能發生。
它在很大程度上取決於tcmalloc代碼在解除分配時的實際作用,以及它如何在該位置使用堆棧周圍的(可能是垃圾)數據。
我也看到過tcmalloc在這種情況下崩潰,以及glibc進入無限循環。 你看到的只是巧合。
首先,你的案件沒有雙重free
。 當object_on_stack超出范圍時,沒有free
調用,只是堆棧指針減少(或者更確切地說,隨着堆棧增長...)。
其次,在刪除期間,TcMalloc應該能夠識別堆棧中的地址不屬於程序堆。 這是free(ptr)
實現的一部分:
const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
Span* span = NULL;
size_t cl = Static::pageheap()->GetSizeClassIfCached(p);
if (cl == 0) {
span = Static::pageheap()->GetDescriptor(p);
if (!span) {
// span can be NULL because the pointer passed in is invalid
// (not something returned by malloc or friends), or because the
// pointer was allocated with some other allocator besides
// tcmalloc. The latter can happen if tcmalloc is linked in via
// a dynamic library, but is not listed last on the link line.
// In that case, libraries after it on the link line will
// allocate with libc malloc, but free with tcmalloc's free.
(*invalid_free_fn)(ptr); // Decide how to handle the bad free request
return;
}
調用invalid_free_fn崩潰。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.