难以跟踪大型程序中的SIGSEGV分段故障
Difficult to track SIGSEGV Segmentation fault in large program
我很抱歉发布了一个被问了很多次的问题(我刚刚读了 10 页),但我找不到解决方案。
我正在分别使用OpenGL和Portaudio开发多线程图形/音频程序。音频线程使用我为音频处理对象制作的库。SIGSEGV 可能发生 20% 的时间(调试时要少得多),并且在使用新的流信息(采样率、矢量大小等)重置音频对象的负载时发生。代码::块 调试器在每次发生故障时将错误声明为来自不同的位置。
这是音频处理循环:
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
的多维数组的音频向量,并可以选择使用一维数组作为控制信号。删除以重新分配内存时,我不小心将所有uVectors(无论类型如何)设置为使用流>通道删除。
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;
}
因此,它删除了它不应该访问的内存,这损坏了堆。我很惊讶段错误没有更频繁地发生,因为这似乎是一个严重的问题。
我可以节省内存,您可以尝试像 Electric Fence(或 DUMA,它的子级)这样的工具,看看它是否是您执行的越界写入。通常,这些类型的段错误(非永久性的,仅在偶尔发生)是先前缓冲区溢出某处的遗物。
您也可以尝试 Valgrind,它将具有与上述 2 种工具相同的效果,但代价是执行速度较慢。
另外,当发生这种情况时,请尝试检查您正在访问的错误地址的值是多少:它看起来有效吗?有时,值可以提供有关您遇到的错误的信息(通常:尝试访问0x12内存,其中0X12是循环:)中的计数器)。
对于堆栈溢出...我建议尝试增加有罪线程的堆栈大小,看看是否重现了该错误。如果没有经过大量的尝试,你已经发现了问题。
至于窗户:
- 如何调试堆损坏错误?
- Win32 下的堆损坏;如何定位?
- https://stackoverflow.com/search?q=windows+memory+corruption&submit=search
我想你只是把它变成了堆栈溢出问题。 :)
严肃地说,像这样的错误通常是访问内存位置的对象的结果,而这些对象不再存在。在您的第一个代码块中,我看到您在堆栈上创建newStream
,其范围仅限于它所属的 if 语句。然后将其复制到取消引用的指针 ( *stream
)。是否为 uStreamInfo
类定义了安全正确的赋值?如果没有显式定义,编译器将悄悄地为对象赋值提供成员复制,这对于简单的基元(如 int
和 double
)是可以的,但不一定适用于动态分配的对象。 *stream
可能会留下一个指向newStream
分配的内存的指针,但当newStream
超出范围时,它已经被释放了。现在该 RAM 上的数据仍然存在,并且暂时看起来是正确的,但是被释放的内存,它随时可能损坏,就像崩溃之前一样。:)
我建议密切关注何时分配和解除分配对象,以及哪些对象拥有哪些其他对象。您还可以采取除以征服的方法,注释掉大部分代码并逐渐启用更多代码,直到您看到崩溃再次开始发生。该错误可能存在于最近重新启用的代码中。
- SIGSEGV, 分段错误. 而 printf() 数组索引的值
- 分段故障 运行C++代码时出现 SIGSEGV
- 在使用堆栈为下一个最大数字编写代码时面临 SIGSEGV(分段错误)
- 为什么在环路条件中使用'<='而不是'<'会产生分段错误 [SIGSEGV]?
- C++ - 程序接收信号SIGSEGV,分段错误.In msvcrt!memcpy () (C:\Windows\S
- sqlite3 程序接收信号 SIGSEGV,分段错误在 sqlite3_get_table ()
- 尝试关闭 SSL 套接字时使用升压 asio 1.64 的分段错误 (SIGSEGV)
- 程序接收信号SIGSEGV,分段错误。使用矢量<string>时
- 程序接收信号SIGSEGV,分段错误.C++列表
- 程序收到信号sigsegv,分段故障.在al_draw_tinted_bitmap中(bitmap = 0x0,tint
- c++分段错误:为什么这个程序给出运行时错误(SIGSEGV)
- SIGSEGV,声明变量时的分段错误错误
- 程序在调用类指针时收到信号SIGSEGV,分段错误
- Mat::at<double>(i,j) SIGSEGV, 分段错误
- 程序接收信号SIGSEGV,输出分段故障
- Qt Creator:通过SIGSEGV的分段错误(C++)
- 难以跟踪大型程序中的SIGSEGV分段故障
- 当迭代通过大串集时,for循环接收到信号SIGSEGV,出现分段故障
- 使用枚举的奇怪SIGSEGV(分段错误)
- 文件 io - C++ SIGSEGV 分段错误在循环中