0

我很抱歉发布了一个已被多次询问的问题(我刚刚阅读了其中的 10 页),但我找不到解决方案。

我正在开发一个分别使用 OpenGL 和 Portaudio 的多线程图形/音频程序。音频线程使用我为音频处理对象制作的库。SIGSEGV 可能发生 20% 的时间(调试时少得多),并且在使用新的流信息(采样率、矢量大小等)重置音频对象的负载时发生。Code::blocks 每次故障发生时,调试器都会将故障声明为来自不同的地方。

这是音频处理循环:

while(true){
    stream->tick();
    menuAudio.tick();
    {
        boost::mutex::scoped_lock lock(*mutex);
        if(channel->AuSwitch.resetAudio){
            uStreamInfo newStream(channel->AuSwitch.newSrate, 
                 channel->AuSwitch.newVSize, channel->AuSwitch.newChans);
            menuAudio.resetStream(&newStream);
            (*stream) = newStream;
            menuAudio.resetStream(stream);
            channel->AuSwitch.resetAudio = false;
        }
    }
}

它检查来自图形线程的信息,告诉它重置音频并运行补丁对象的 resetStream 函数,这基本上是音频对象的向量并运行它们中的每一个:

void uPatch::resetStream(uStreamInfo* newStream)
{
    for(unsigned i = 0; i < numObjects; ++i){
/*This is where it reports this error: Program received signal SIGSEGV,  
Segmentation fault. Variables: i = 38, numObjects = 43 */
        objects[i]->resetStream(newStream); 
    }
}  

有时它会声明 SIGSEGV 来自不同的位置,但由于在使用调试器运行时它很少会出错,这是我唯一能发生的。

由于对象太多,我不会发布他们所有的重置代码,但作为一个例子:

void uSamplerBuffer::resetStream(uStreamInfo* newStream)
{
    audio.set(newStream, false);
    control.set(newStream, true);
    stream = newStream;
    incr = (double)buffer->sampleRate / (double)stream->sampleRate;
    index = 0;
}

audio.set 代码在哪里:

void uVector::set(uStreamInfo* newStream, bool controlVector)
{
    if(vector != NULL){
        for(unsigned i = 0; i < stream->channels; ++i)
            delete[] vector[i];
        delete vector;
    }
    if(controlVector)
        channels = 1;
    else
        channels = newStream->channels;
    vector = new float*[channels];
    for(unsigned i = 0; i < channels; ++i)
        vector[i] = new float[newStream->vectorSize];
    stream = newStream;
    this->flush();
}

我最好的猜测是这是一个堆栈溢出问题,因为它只发生在大量对象上,并且它们每个都单独运行良好。也就是说,音频流本身运行良好并且以类似的方式运行。此外,循环objects[i]->resetStream(newStream);应该在每个成员函数之后弹出堆栈,所以我不明白为什么它会 SIGSEGV。

有什么意见/建议吗?

编辑:

这是一个错误删除的内存问题。应用程序验证程序在错误点使其出现故障,而不是识别为源自其他位置的偶尔故障。问题出在 uVector 流设置函数中,因为该类的目的是用于使用多维数组的音频向量stream->channels,并可以选择使用一维数组作为控制信号。删除以重新分配内存时,我不小心设置了所有 uVector,无论使用流-> 通道删除的类型如何。

if(vector != NULL){
    for(unsigned i = 0; i < stream->channels; ++i)
        delete[] vector[i];
    delete vector;
}

它应该在哪里:

if(vector != NULL){
    for(unsigned i = 0; i < this->channels; ++i)
        delete[] vector[i];
    delete vector;
}

所以它正在删除它不应该访问的内存,这破坏了堆。我很惊讶段错误并没有更频繁地发生,因为这似乎是一个严重的问题。

4

2 回答 2

0

我可以节省内存,您可以尝试使用Electric Fence(或DUMA,它的孩子)之类的工具来查看它是否是您执行的越界写入。通常这些类型的段错误(非永久性的,仅有时发生)是某个地方先前缓冲区溢出的遗留物。

您也可以尝试使用 Valgrind,它的效果与上述 2 个工具相同,但执行速度较慢。

另外,尝试检查发生这种情况时您正在访问的错误地址的值是多少:它看起来是否有效?有时,一个值可以为您遇到的错误提供非常丰富的信息(通常:尝试访问 0x12 处的内存,其中 0X12 是循环中的计数器 :))。

对于堆栈溢出...我建议尝试增加被指控线程的堆栈大小,看看是否重现了该错误。如果不是经过多次尝试,您就会发现问题所在。

至于窗户:

于 2012-04-26T06:32:13.253 回答
0

我认为您只是将其作为堆栈溢出问题。:)

严肃地说,像这样的错误通常是在它们不再存在的内存位置访问对象的结果。在您的第一个代码块中,我看到您newStream在堆栈上创建,其范围仅限于它所属的 if 语句。然后将其复制到取消引用的指针 ( *stream)。是否为班级定义了安全且正确的作业uStreamInfo?如果没有明确定义,编译器会悄悄地为对象分配提供成员副本,这对于像intand这样的简单原语是可以的double,但对于动态分配的对象则不一定。*stream可能会留下一个指向由 分配的内存的指针newStream,但在newStream超出范围。现在,该 RAM 中的数据仍然存在,并且暂时看起来是正确的,但由于内存被释放,它可能随时损坏,就像崩溃前一样。:)

我建议密切注意何时分配和解除分配对象,以及哪些对象拥有哪些其他对象。您还可以采取分而治之的方法,注释掉大部分代码并逐渐启用更多代码,直到您看到崩溃再次开始发生。该错误可能出现在最近重新启用的代码中。

于 2012-04-26T06:41:33.653 回答