2015-12-25 53 views
0

我有一個程序(全碼here),其圍繞所述第四萬六千迭代退出:C++程序退出時沒有錯誤。如何調試?

{ 
    PROCESSER<MONO_CONT> processer; 
    c_start = std::clock(); 
    for (unsigned long long i = 0; i < iterations; i++) { 
     BloombergLP::bdlma::BufferedSequentialAllocatoralloc(pool, sizeof(pool)); 
     MONO_CONT* container = new(alloc) MONO_CONT(&alloc); 
     container->reserve(elements); 
     processer(container, elements); 
    } 
    c_end = std::clock(); 
    std::cout << (c_end - c_start) * 1.0/CLOCKS_PER_SEC << " "; 
} 

在這種情況下,MONO_CONTvector<string, scoped_allocator_adaptor<alloc_adaptor<BloombergLP::bdlma::BufferedSequentialAllocator>>>。 我的理解是,scoped_allocator_adaptor將確保提供的分配器將用於分配正在傳入的字符串,從而確保在每次循環迭代結束時取消分配字符串(避免@ 1201ProgramAlarm針對該問題的建議)。 alloc_adapter只是一個使Bloomberg分配器符合正確接口的包裝。

PROCESSER是以下模板函數對象,只是執行模板容器上的一些基本操作,MONO_CONT

template<typename DS2> 
struct process_DS2 { 
    void operator() (DS2 *ds2, size_t elements) { 
     escape(ds2); 
     for (size_t i = 0; i < elements; i++) { 
      ds2->emplace_back(&random_data[random_positions[i]], random_lengths[i]); 
     } 
     clobber(); 
    } 
}; 

注意escapeclobber只是一些魔法做什麼比擊敗優化外(見this talk如果你有興趣)。 random_data只是包含垃圾的char的數組。 random_positions將有效指數定義爲random_datarandom_lengths定義了從random_positions中相應位置開始的有效字符串長度(不會超出垃圾數據的末尾)。

我有一個運行的確切迭代次數相同類似的代碼,而不會失敗:

{ 
    PROCESSER<MONO_CONT> processer; 
    c_start = std::clock(); 
    for (unsigned long long i = 0; i < iterations; i++) { 
     BloombergLP::bdlma::BufferedSequentialAllocator alloc(pool, sizeof(pool)); 
     MONO_CONT container(&alloc); 
     container.reserve(elements); 
     processer(&container, elements); 
    } 
    c_end = std::clock(); 
    std::cout << (c_end - c_start) * 1.0/CLOCKS_PER_SEC << " "; 
} 

兩個片段之間的主要區別在於,第一,我是new荷蘭國際集團的集裝箱進入分配器,然後將分配器傳遞給容器,依靠分配器的銷燬來釋放容器的所有內存(而不必實際調用容器本身的析構函數)。在第二個片段中,我允許在循環的每次迭代結束時通過超出範圍來更自然地破壞容器。

我正在用Clang構建它,運行在Debian的Docker容器中。關於這個問題可能是什麼或者我該如何開始調試的建議?

+1

第一個示例使用'placement-new'。那麼對析構函數的顯式調用在哪裏? https://isocpp.org/wiki/faq/dtors#placement-new – PaulMcKenzie

+0

@PaulMcKenzie據我所知,它被定義爲不調用析構函數,因爲分配器的析構函數清理內存,我從來沒有訪問內存處理後的容器被丟棄。看看第3章的最後3段,瞭解我爲什麼這樣做的更多細節:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0089r0.pdf – GBleaney

+0

如果您擔心分配器效率問題,可以考慮在循環外部創建'MONO_CONT'對象,在每次迭代後清空(),然後'reserve()'達到高水位,很少需要進行任何分配。 –

回答

1

當你依靠分配器的破壞要解除分配container內存,這不會釋放被包含string小號使用的內存,這將不使用分配器爲vector,但將使用全球堆(new)。當程序運行內存不足時,它會退出而不報告任何內容,可能是因爲它沒有足夠的內存可用來執行此操作。

在第二個版本中container被銷燬,當vector被銷燬時,將釋放分配的字符串。

至於如何調試這樣的事情,通常的建議是「嘗試將它通過調試器」,這是一個開始。如果在調試器中運行附件,則在創建或拋出std::bad_alloc異常時它可能會中斷。你可以監視進程的內存使用情況。

+0

我添加了一些額外的說明,我的帖子解釋了我使用'scoped_allocator_adaptor',我認爲應該有我在這裏覆蓋 – GBleaney

+0

經過一些額外的挖掘,看起來你可能是對的。我忘了模板字符串以接受來自'scoped_allocator_adaptor'的自定義分配器,所以它不是去堆 – GBleaney