我现在看起来像是无法解决的EXC_BAD_ACCESS问题。 我已经尝试过启用NSZombie,因为在许多帖子中似乎都是建议但是我正在处理c指针而不是obj c对象所以我没有得到任何有用的调试信息。
我的代码工作的方式是,在它需要来自磁盘的一些音频之前,我分离一个新的posix线程,传递一个指向我想要的音频信息的指针。然后我读了一些样品。 我选择posix而不是NSThread或NSOperation的原因是因为它似乎表现得更快。我的音频非常密集,所以我需要尽可能快地读取音频。
如何修复此错误的访问错误?它不会一直发生。有时它似乎发生在应用程序非常繁忙时。偶尔它根本不会发生。
无论如何,我可以试着快速解决这个问题吗?我怎么能调查这种情况的原因呢?
修改这是我提出的单独问题的链接,但它与同一问题有关
[线索强烈的io] [1]
//detachnewthread gets called from remoteio callback
void detachnewthread(AudioSourceOBJ str)
{
//..... code removed for brevity
if(str)
{
int rc;
rc = pthread_create(&str->thread, NULL, FetchAudio, (void *)str);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
}
void *FetchAudio(void *threadid)
{ AudioSourceOBJ soundptr = threadid;
AudioUnitSampleType *outSamplesChannelLeft;
AudioUnitSampleType *outSamplesChannelRight;
outSamplesChannelLeft = (AudioUnitSampleType *) soundptr->queuebuffer->ABL->mBuffers[0].mData;
outSamplesChannelRight = (AudioUnitSampleType *)soundptr->queuebuffer->ABL->mBuffers[0].mData;
// ExtAudioFileRef audioFileRef;
// result= ExtAudioFileOpenURL(str->path, &str->audioFileObject);
AudioStreamBasicDescription importFormat = {0};
size_t bytesPerSample = sizeof (AudioUnitSampleType);
// Fill the application audio format struct's fields to define a linear PCM,
// stereo, noninterleaved stream at the hardware sample rate.
importFormat.mFormatID = kAudioFormatLinearPCM;
importFormat.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical;
importFormat.mBytesPerPacket = bytesPerSample;
importFormat.mFramesPerPacket = 1;
importFormat.mBytesPerFrame = bytesPerSample;
importFormat.mChannelsPerFrame = 2; // 2 indicates stereo
importFormat.mBitsPerChannel = 8 * bytesPerSample;
importFormat.mSampleRate = 44100;
ExtAudioFileSetProperty (
engineDescribtion.audiofilerefs[soundptr->audioindex],
kExtAudioFileProperty_ClientDataFormat,
sizeof (importFormat),
&importFormat
);
UInt32 numberofframestoread=(soundptr->amounttoread);
AudioBufferList *bufferList;
bufferList = (AudioBufferList *) malloc (
sizeof (AudioBufferList) + sizeof (AudioBuffer) * (1)
);
// initialize the mNumberBuffers member
bufferList->mNumberBuffers = 2;
// initialize the mBuffers member to 0
AudioBuffer emptyBuffer = {0};
size_t arrayIndex;
for (arrayIndex = 0; arrayIndex < 2; arrayIndex++) {
bufferList->mBuffers[arrayIndex] = emptyBuffer;
}
// set up the AudioBuffer structs in the buffer list
bufferList->mBuffers[0].mNumberChannels = 1;
bufferList->mBuffers[0].mDataByteSize = numberofframestoread * sizeof (AudioUnitSampleType);
bufferList->mBuffers[0].mData = (AudioUnitSampleType*)calloc(numberofframestoread, sizeof(AudioUnitSampleType));
bufferList->mBuffers[1].mNumberChannels = 1;
bufferList->mBuffers[1].mDataByteSize = numberofframestoread * sizeof (AudioUnitSampleType);
bufferList->mBuffers[1].mData = (AudioUnitSampleType*)calloc(numberofframestoread, sizeof(AudioUnitSampleType));
AudioUnitSampleType *inSamplesChannelLeft=bufferList->mBuffers[0].mData;
AudioUnitSampleType *inSamplesChannelRight=bufferList->mBuffers[1].mData;
// UInt32 read=(UInt32)soundptr->fetchsample;
UInt32 read_plus_half_buffer=soundptr->fetchsample;
UInt32 readdestination= read_plus_half_buffer+numberofframestoread;
UInt32 actualsamplesread=0;
actualsamplesread=numberofframestoread;
if (readdestination>soundptr->perfectframecount) {
UInt32 readinpt1=0;
UInt32 readoutpt1=0;
UInt32 readinpt2=0;
UInt32 readoutpt2=0;
Float32 readtillendamount=0;
readinpt1=read_plus_half_buffer;
readoutpt1=soundptr->perfectframecount;
readinpt2=0;
if(read_plus_half_buffer>soundptr->perfectframecount)
{
readtillendamount=numberofframestoread;
readinpt1=read_plus_half_buffer-soundptr->perfectframecount;
}else
{
readtillendamount=soundptr->perfectframecount - readinpt1;
readoutpt2=numberofframestoread-readtillendamount;
}
actualsamplesread= readtillendamount;
ExtAudioFileSeek(engineDescribtion.audiofilerefs[soundptr->audioindex], readinpt1);
ExtAudioFileRead(engineDescribtion.audiofilerefs[soundptr->audioindex],&actualsamplesread , bufferList);
int writeposition=soundptr->queuebuffer->position;
for (int i=0; i<actualsamplesread; i++) {
outSamplesChannelLeft[writeposition]=inSamplesChannelLeft[i];
outSamplesChannelRight[writeposition]=inSamplesChannelRight[i];
writeposition++;
}
if (actualsamplesread!=readtillendamount) {
UInt32 newzeroamount= readtillendamount-actualsamplesread;
for (int j=0; j<newzeroamount; j++) {
outSamplesChannelLeft[writeposition]=0;
outSamplesChannelRight[writeposition]=0;
writeposition++;
}
}
bufferList->mBuffers[1].mDataByteSize = readoutpt2 * sizeof (AudioUnitSampleType);
bufferList->mBuffers[0].mDataByteSize = readoutpt2 * sizeof (AudioUnitSampleType);
ExtAudioFileSeek(engineDescribtion.audiofilerefs[soundptr->audioindex], 0);
ExtAudioFileRead(engineDescribtion.audiofilerefs[soundptr->audioindex],&readoutpt2 , bufferList);
for (int k=0; k<readoutpt2; k++) {
outSamplesChannelLeft[writeposition]=inSamplesChannelLeft[k];
outSamplesChannelRight[writeposition]=inSamplesChannelRight[k];
writeposition++;
}
}else if(readdestination<=soundptr->perfectframecount){
ExtAudioFileSeek(engineDescribtion.audiofilerefs[soundptr->audioindex], read_plus_half_buffer);
bufferList->mBuffers[1].mDataByteSize = actualsamplesread * sizeof (AudioUnitSampleType);
bufferList->mBuffers[0].mDataByteSize = actualsamplesread * sizeof (AudioUnitSampleType);
// crash happens here
if(bufferList)
{
assert( ExtAudioFileRead(engineDescribtion.audiofilerefs[soundptr->audioindex],&actualsamplesread , bufferList));
}else
{
printf("NO BUFFER");
}
int writeposition=soundptr->queuebuffer->position;
for (int i=0; i<actualsamplesread; i++) {
outSamplesChannelLeft[writeposition]=inSamplesChannelLeft[i];
outSamplesChannelRight[writeposition]=inSamplesChannelRight[i];
writeposition++;
}
if (actualsamplesread!=numberofframestoread) {
int zerosamples=0;
zerosamples=numberofframestoread-actualsamplesread;
for (int j=0; j<zerosamples; j++) {
outSamplesChannelLeft[writeposition]=0;
outSamplesChannelRight[writeposition]=0;
writeposition++;
}
}
}else
{
printf("unknown condition");
}
free(bufferList->mBuffers[0].mData);
free(bufferList->mBuffers[1].mData);
free(bufferList);
bufferList=nil;
soundptr->queuebuffer->isreading=NO;
// pthread_detach(soundptr->thread);
// free(&soundptr->m_lock);
return 0;
// pthread_exit(NULL);
}
修改2
O.K我已经想出了如何使用malloc历史。我有一个很大的跟踪声明。这是我第一次见过这样的事情。我不知道如何使用它来帮助自己。
ALLOC 0x6c67000-0x6c67fd7 [size=4056]: thread_a019c540 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSource1 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ | migHelperRecievePortCallout | _XReceivedStatusBarDataAndActions | _UIStatusBarReceivedStatusBarDataAndActions | -[UIStatusBarServer _receivedStatusBarData:actions:] | -[UIStatusBarForegroundView setStatusBarData:actions:animated:] | -[UIStatusBarLayoutManager updateItemsWithData:actions:animated:] | -[UIStatusBarLayoutManager _updateItemView:withData:actions:animated:] | -[UIStatusBarItemView updateContentsAndWidth] | -[UIStatusBarTimeItemView contentsImageForStyle:] | -[UIStatusBarItemView drawText:forStyle:] | -[UIStatusBarItemView drawText:forStyle:forWidth:lineBreakMode:letterSpacing:] | -[NSString(UIStringDrawing) drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:] | -[NSString(UIStringDrawing) drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:] | -[NSString(WebStringDrawing) _web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:] | -[NSString(WebStringDrawing) __web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:measureOnly:] | -[NSString(WebStringDrawing) __web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:measureOnly:renderedStringOut:] | drawAtPoint(unsigned short const*, int, WebCore::FloatPoint const&, WebCore::Font const&, WebCore::GraphicsContext*, WebCore::BidiStatus*, int) | WebCore::Font::drawSimpleText(WebCore::GraphicsContext*, WebCore::TextRun const&, WebCore::FloatPoint const&, int, int) const | WebCore::Font::drawGlyphBuffer(WebCore::GraphicsContext*, WebCore::GlyphBuffer const&, WebCore::TextRun const&, WebCore::FloatPoint&) const | WebCore::Font::drawGlyphs(WebCore::GraphicsContext*, WebCore::SimpleFontData const*, WebCore::GlyphBuffer const&, int, int, WebCore::FloatPoint const&, bool) const | WebCore::showGlyphsWithAdvances(WebCore::FontPlatformData const&, CGContext*, unsigned short const*, CGSize const*, unsigned long) | CGContextShowGlyphsWithAdvances | draw_glyphs | ripc_DrawGlyphs | ripc_RenderGlyphs | CGGlyphLockLockGlyphBitmaps | create_missing_bitmaps | CGFontCreateGlyphBitmap8 | aa_create | malloc | malloc_zone_malloc
----
FREE 0x6c67000-0x6c67fd7 [size=4056]: thread_a019c540 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSource1 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ | migHelperRecievePortCallout | _XReceivedStatusBarDataAndActions | _UIStatusBarReceivedStatusBarDataAndActions | -[UIStatusBarServer _receivedStatusBarData:actions:] | -[UIStatusBarForegroundView setStatusBarData:actions:animated:] | -[UIStatusBarLayoutManager updateItemsWithData:actions:animated:] | -[UIStatusBarLayoutManager _updateItemView:withData:actions:animated:] | -[UIStatusBarItemView updateContentsAndWidth] | -[UIStatusBarTimeItemView contentsImageForStyle:] | -[UIStatusBarItemView drawText:forStyle:] | -[UIStatusBarItemView drawText:forStyle:forWidth:lineBreakMode:letterSpacing:] | -[NSString(UIStringDrawing) drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:] | -[NSString(UIStringDrawing) drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:] | -[NSString(WebStringDrawing) _web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:] | -[NSString(WebStringDrawing) __web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:measureOnly:] | -[NSString(WebStringDrawing) __web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:measureOnly:renderedStringOut:] | drawAtPoint(unsigned short const*, int, WebCore::FloatPoint const&, WebCore::Font const&, WebCore::GraphicsContext*, WebCore::BidiStatus*, int) | WebCore::Font::drawSimpleText(WebCore::GraphicsContext*, WebCore::TextRun const&, WebCore::FloatPoint const&, int, int) const | WebCore::Font::drawGlyphBuffer(WebCore::GraphicsContext*, WebCore::GlyphBuffer const&, WebCore::TextRun const&, WebCore::FloatPoint&) const | WebCore::Font::drawGlyphs(WebCore::GraphicsContext*, WebCore::SimpleFontData const*, WebCore::GlyphBuffer const&, int, int, WebCore::FloatPoint const&, bool) const | WebCore::showGlyphsWithAdvances(WebCore::FontPlatformData const&, CGContext*, unsigned short const*, CGSize const*, unsigned long) | CGContextShowGlyphsWithAdvances | draw_glyphs | ripc_DrawGlyphs | ripc_RenderGlyphs | CGGlyphLockLockGlyphBitmaps | create_missing_bitmaps | CGFontCreateGlyphBitmap8 | aa_destroy | free
ALLOC 0x6c67000-0x6c67fff [size=4096]: thread_b024f000 |thread_start | _pthread_start | __NSThread__main__ | -[NSThread main] | -[FirstViewController checkstate:] | CALayer_setter_kCAValueFloat | CALayer_setter | CA::Transaction::ensure_compat() | CA::Transaction::create() | malloc | malloc_zone_malloc
----
FREE 0x6c67000-0x6c67fff [size=4096]: thread_b024f000 |thread_start | _pthread_start | __NSThread__main__ | -[NSString compare:options:] | _pthread_exit | _pthread_tsd_cleanup | free
ALLOC 0x6c67000-0x6c67fff [size=4096]: thread_b0353000 |thread_start | _pthread_start | __NSThread__main__ | -[NSThread main] | -[FirstViewController checkstate:] | CALayer_setter_kCAValueFloat | CALayer_setter | CA::Transaction::ensure_compat() | CA::Transaction::create() | malloc | malloc_zone_malloc
----
FREE 0x6c67000-0x6c67fff [size=4096]: thread_b0353000 |thread_start | _pthread_start | __NSThread__main__ | -[NSString compare:options:] | _pthread_exit | _pthread_tsd_cleanup | free
ALLOC 0x6c67000-0x6c67fff [size=4096]: thread_b0763000 |thread_start | _pthread_start | FetchAudio | ExtAudioFileRead | ExtAudioFile::Read(unsigned long, unsigned long&, AudioBufferList*) | AudioConverterFillComplexBuffer | BufferedAudioConverter::FillBuffer(unsigned long&, AudioBufferList&, AudioStreamPacketDescription*) | AudioConverterChain::RenderOutput(CABufferList*, unsigned long, unsigned long&, AudioStreamPacketDescription*) | BufferedAudioConverter::FillBuffer(unsigned long&, AudioBufferList&, AudioStreamPacketDescription*) | CBRConverter::RenderOutput(CABufferList*, unsigned long, unsigned long&, AudioStreamPacketDescription*) | BufferedAudioConverter::GetInputBytes(unsigned long, unsigned long&, CABufferList const*&) | CABufferList::AllocateBuffers(unsigned long) | operator new[](unsigned long) | operator new(unsigned long) | malloc | malloc_zone_malloc
----
FREE 0x6c67000-0x6c67fff [size=4096]: thread_b0763000 |thread_start | _pthread_start | FetchAudio | ExtAudioFileRead | ExtAudioFile::Read(unsigned long, unsigned long&, AudioBufferList*) | AudioConverterFillComplexBuffer | BufferedAudioConverter::FillBuffer(unsigned long&, AudioBufferList&, AudioStreamPacketDescription*) | AudioConverterChain::RenderOutput(CABufferList*, unsigned long, unsigned long&, AudioStreamPacketDescription*) | BufferedAudioConverter::FillBuffer(unsigned long&, AudioBufferList&, AudioStreamPacketDescription*) | CBRConverter::RenderOutput(CABufferList*, unsigned long, unsigned long&, AudioStreamPacketDescription*) | BufferedAudioConverter::GetInputBytes(unsigned long, unsigned long&, CABufferList const*&) | free
ALLOC 0x6c67000-0x6c67fff [size=4096]: thread_b0a6f000 |thread_start | _pthread_start | FetchAudio | ExtAudioFileRead | ExtAudioFile::Read(unsigned long, unsigned long&, AudioBufferList*) | AudioConverterFillComplexBuffer | BufferedAudioConverter::FillBuffer(unsigned long&, AudioBufferList&, AudioStreamPacketDescription*) | AudioConverterChain::RenderOutput(CABufferList*, unsigned long, unsigned long&, AudioStreamPacketDescription*) | BufferedAudioConverter::FillBuffer(unsigned long&, AudioBufferList&, AudioStreamPacketDescription*) | CBRConverter::RenderOutput(CABufferList*, unsigned long, unsigned long&, AudioStreamPacketDescription*) | BufferedAudioConverter::GetInputBytes(unsigned long, unsigned long&, CABufferList const*&) | CABufferList::AllocateBuffers(unsigned long) | operator new[](unsigned long) | operator new(unsigned long) | malloc | malloc_zone_malloc
----
FREE 0x6c67000-0x6c67fff [size=4096]: thread_b0a6f000 |thread_start | _pthread_start | FetchAudio | ExtAudioFileRead | ExtAudioFile::Read(unsigned long, unsigned long&, AudioBufferList*) | AudioConverterFillComplexBuffer | BufferedAudioConverter::FillBuffer(unsigned long&, AudioBufferList&, AudioStreamPacketDescription*) | AudioConverterChain::RenderOutput(CABufferList*, unsigned long, unsigned long&, AudioStreamPacketDescription*) | BufferedAudioConverter::FillBuffer(unsigned long&, AudioBufferList&, AudioStreamPacketDescription*) | CBRConverter::RenderOutput(CABufferList*, unsigned long, unsigned long&, AudioStreamPacketDescription*) | BufferedAudioConverter::GetInputBytes(unsigned long, unsigned long&, CABufferList const*&) | free
ALLOC 0x6c67000-0x6c67fff [size=4096]: thread_b0081000 |thread_start | _pthread_start | __NSThread__main__ | -[NSThread main] | -[FirstViewController checkstate:] | CALayer_setter_kCAValueFloat | CALayer_setter | CA::Transaction::ensure_compat() | CA::Transaction::create() | malloc | malloc_zone_malloc
----
FREE 0x6c67000-0x6c67fff [size=4096]: thread_b0081000 |thread_start | _pthread_start | __NSThread__main__ | -[NSString compare:options:] | _pthread_exit | _pthread_tsd_cleanup | free
答案 0 :(得分:1)
我注意到代码中有以下几行:
bufferList = (AudioBufferList *) malloc (
sizeof (AudioBufferList) + sizeof (AudioBuffer) * (1)
);
// initialize the mNumberBuffers member
bufferList->mNumberBuffers = 2;
你正在使用AudioBufferList来获得一个AudioBuffer的容量,但后来表明它实际上有两个。尝试将“*(1)”更改为“*(2)”。
除此之外,你不应该在线程中执行malloc或ExtAudioFileOpen,因为这会占用时间。如果您可以设置预先执行malloc和ExtAudioFileOpen并将它们保存在文件的结构数组中,您可能会发现性能/稳定性有所提高。
我可能没有完全正确地阅读代码,因为它看起来格式有些混乱,但我希望这会有所帮助。
答案 1 :(得分:1)
你可以通过找到它并找出错误的原因来解决这个问题,而不是通过try / catch来解决这个问题。
Guard Malloc可以帮助您识别程序中的许多问题。它是一个诊断选项,您可以在Xcode中启用它。当您尝试读取或写入您不拥有的内存时,该选项的目的是失败,使得程序的哪个部分导致问题比通常更清晰。完整详情:man guardmalloc
。第一步是纠正所有问题,guardmalloc指出。您应该能够在没有这些问题的情况下运行您的应用数小时。
如果您希望异常和运行时检查可以帮助您更早地识别这些问题(值得您考虑),请考虑使用C ++而不是C来实现。
<强>更新强>
如果它是有问题的分配的堆分配,那么malloc日志记录可能会对您有所帮助。启用malloc日志记录并且调试器暂停执行时,只需使用malloc_history
查看分配的调用堆栈。 malloc_history将查找日志中的地址并转储alloc创建的callstack。从那里,你只需按照你的程序中的分配流程找到你错了。
答案 2 :(得分:1)
我最终找到了解决这个问题的方法。每次我需要音频时,我都会创建一个新线程来获取音频。在线程为特定缓冲区获取音频时,同一缓冲区将再次请求数据,导致同时访问相同的缓冲区,因此exc_bad_access。
我通过只有一个线程等待并通过posix条件发出信号来获取数据来解决这个问题。
这里的所有答案都很有用,并帮助我学习了很多关于调试的知识。谢谢你们..
答案 3 :(得分:0)
这个问题几乎肯定会发生,因为你的阅读记忆是你不应该的。因此EXC_BAD_ACCESS
。重要的是缓冲区的大小和您正在读取的内存量都是正确的。例如,如果您尝试读取超过缓冲区的值,则会收到错误。
在ExtAudioFileRead
中,&readoutpt2
处的值应指定帧数。你确定这个值是否正确? bufferList
大到足以存储该帧数吗?当您读取数据时,您是否正在通过bufferList
推进指针,并且您推进的数量是否正确?
您是否根据基础类型正确分配内存?例如,您的音频数据是整数还是浮点格式?
基本上,一切都需要正确加起来,否则你会在某个地方放一个缓冲区!
尝试追踪内存问题的另一个工具是guard malloc
。您可以在此处找到更多信息Enabling the Malloc Debugging Features