C ++程序退出时没有错误。怎么调试?

时间:2015-12-25 01:33:10

标签: c++ memory-management allocator

我有一个程序(完整代码here),它正在第46000次迭代中退出:

{
    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&#39;对问题的建议)。 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_lengthsrandom_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容器放入分配器中,然后将分配器传递给容器,依赖于分配器&#39;破坏以释放容器的所有内存(无需实际调用容器本身的析构函数)。在第二个片段中,我通过在循环的每次迭代结束时超出范围来允许更自然地破坏容器。

我用Clang构建它,在Debian上的Docker容器中运行。关于问题可能是什么或如何开始调试的建议?

1 个答案:

答案 0 :(得分:1)

当您依靠分配器的销毁来释放为container分配的内存时,这将不会释放包含string所使用的内存,而这些内存将不会使用分配器vector但将使用全局堆(new)。当程序内存不足时,它会退出而不报告任何内容,可能是因为它没有足够的可用内存。

在你的第二个版本中container被销毁,这将在vector被销毁时释放分配的字符串。

至于如何调试这样的东西,“尝试通过调试器中的步进”的通常建议是一个开始。如果在调试器中运行附加,则在创建或抛出std::bad_alloc异常时可能会中断。您可以监控进程的内存使用情况。