Iphone 间歇性extaudiofileread exc\u访问错误
我有一个目前看来无法解决的EXC\u BAD\u访问问题。 我尝试过启用NSZombie,这似乎是许多帖子中的建议,但我处理的是c指针,而不是objc对象,因此我没有得到任何有用的调试信息 我的代码的工作方式是,在需要磁盘上的一些音频之前,我分离一个新的posix线程,向它传递一个指向我想要的音频信息的指针。然后我看了一些样品。 我之所以选择posix而不是NSThread或NSOperation,是因为它似乎执行得更快。我的音频是cpu密集型的,所以我需要尽快阅读音频 如何修复此错误的访问错误?它并非总是发生。有时它似乎发生在应用程序非常繁忙的时候。偶尔它根本不会发生 不管怎样,我可以试着抓住它作为一个快速解决方案吗?我还可以如何调查发生这种情况的原因 编辑这是我问的一个单独问题的链接,但它与同一个问题相关 [高强度io线程][1]Iphone 间歇性extaudiofileread exc\u访问错误,iphone,ios,exc-bad-access,Iphone,Ios,Exc Bad Access,我有一个目前看来无法解决的EXC\u BAD\u访问问题。 我尝试过启用NSZombie,这似乎是许多帖子中的建议,但我处理的是c指针,而不是objc对象,因此我没有得到任何有用的调试信息 我的代码的工作方式是,在需要磁盘上的一些音频之前,我分离一个新的posix线程,向它传递一个指向我想要的音频信息的指针。然后我看了一些样品。 我之所以选择posix而不是NSThread或NSOperation,是因为它似乎执行得更快。我的音频是cpu密集型的,所以我需要尽快阅读音频 如何修复此错误的访问错误
//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);
这个问题几乎肯定会发生,因为你不应该读取内存。因此,
EXC\u BAD\u ACCESS
。重要的是,缓冲区的大小和你正在读取的内存量都是正确的。例如,如果你试图读取超过缓冲区值的内存,你会收到一个错误
在ExtAudioFileRead
中,&readoutpt2
处的值应指定帧数。您确定该值正确吗?bufferList
是否足够大以存储该帧数?在读取数据时是否将指针向前移动bufferList
,前进的量是否正确
您是否根据基础类型正确分配内存?例如,音频数据是整数格式还是浮点格式
基本上,所有的东西都需要正确地相加,否则你会在某个地方失去缓冲
另一个尝试跟踪内存问题的工具是
guard malloc
。您可以在此处找到更多信息我注意到代码中有以下几行:
bufferList = (AudioBufferList *) malloc (
sizeof (AudioBufferList) + sizeof (AudioBuffer) * (1)
);
// initialize the mNumberBuffers member
bufferList->mNumberBuffers = 2;
您正在使AudioBufferList具有一个AudioBuffer的容量,但随后表明它实际上有两个。请尝试将“*(1)”更改为“*(2)”
除此之外,您不应该在线程中执行malloc或ExtAudioFileOpen,因为它们会占用时间。如果您能够设法预先执行malloc和ExtAudioFileOpen,并将它们保存在文件的结构数组中,您可能会发现性能/稳定性有所提高
我可能没有完全正确地阅读代码,因为它的格式似乎有点混乱,但我希望这会有所帮助。您可以通过定位代码并找出错误原因来解决此问题,而不是尝试/捕获 Guard Malloc可以帮助您识别程序中的许多问题。这是一个可以在Xcode中启用的诊断选项。该选项的目的是在您尝试读取或写入您不拥有的内存时失败,使程序的哪个部分导致问题比通常更清楚。完整详细信息:
man guardmalloc
。第一个step是纠正guardmalloc指出的所有问题。您应该能够在没有这些问题的情况下运行应用程序数小时
如果您希望异常和运行时检查帮助您在前面(这些问题值得考虑)识别这些问题,请考虑C++实现而不是C实现。 更新
如果有问题的是堆分配,那么malloc日志记录可能会对您有所帮助。当启用malloc日志记录并且调试器暂停执行时,只需使用
malloc\u history
查看分配的调用堆栈。malloc\u history将查找日志中的地址并转储alloc创建的调用堆栈。从那里,您只需按照程序中的分配流程来查找错误所在。我最终找到了这个问题的解决方案。每次需要音频时,我都会创建一个新线程来获取音频。有时,当线程为特定缓冲区获取音频时,同一缓冲区会再次请求数据同一缓冲区中的数据不能同时访问,因此exc\u访问错误
我解决了这个问题,只让一个线程等待,并被通知使用posix条件获取数据
这里的所有答案都很有用,并帮助我了解了很多调试方面的知识。谢谢各位。是的,我确定readoutpt2值正确,我的bufferlist也是如此。示例的格式是什么?整数还是浮点数?您对缓冲区分配的计算是什么?有多少个通道?示例是有符号的16位整数,2个通道关于音频。作为一个最好的猜测,你会说问题与缓冲区列表有关,而不是从磁盘读取的实际音频?如果我同时访问8个音频源,一切都很好。除此之外,我得到了错误。是否可能是由于缺乏资源,线程中的代码没有完全执行,例如:创建缓冲区我会说它比我与缓冲区有关。缓冲区有多大?你是如何计算它们的大小的?每个缓冲区的最大大小是25600个样本*4字节。我在文章中包含了完整的函数。可能更容易查看,而不是试图解释。“似乎执行得更快”-除非你创建线程非常快,否则我非常怀疑用以创建你的线程会影响它们的性能。但是,请用一些基准来证明我是错误的;)你会考虑多快?我每秒要分离大约16到24个线程。这是不是太多了?我会觉得有点过分了。我会考虑重新思考这个体系结构。线程将开始超过th的好处
bufferList = (AudioBufferList *) malloc (
sizeof (AudioBufferList) + sizeof (AudioBuffer) * (1)
);
// initialize the mNumberBuffers member
bufferList->mNumberBuffers = 2;