我正在尝试使用我正在开发的应用来追踪冻结问题。我可能处于NSAutoreleasePool的深层,并且搞砸了。
该应用正在播放midi文件。如果我注释掉下面使用NSAutoreleasePool的“simRespondToFileNote”代码,它就不会冻结。如果我让代码运行,它会在看似随机的点上冻结崩溃日志/控制台输出似乎并不表示问题发生的位置。
以下是程序流程:
我正在使用Bass midi lib(C lib);它在自己的线程中播放midi文件。
当发生midi事件时,会触发回调并将midi事件数据包装在NSDictionary中并将其路由到主线程,以便我可以进行UI更新和其他一些操作。
以下是执行路由的代码:
- (void)forwardFileNoteIn:(int) note withVelocity: (int) velocity
{
int position = BASS_ChannelGetPosition(midiFileStream, BASS_POS_MIDI_TICK);
float percent = ((float)position / (float)totalTicks);
int ticksInLoop = outLoopTick - inLoopTick;
QWORD bytes=BASS_ChannelGetPosition(midiFileStream, BASS_POS_BYTE); // get position in bytes
double seconds=BASS_ChannelBytes2Seconds(midiFileStream, bytes); // translate to seconds
int timeStamp =seconds*1000; // translate to milliseconds
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDictionary *midiData = [NSDictionary dictionaryWithObjectsAndKeys:
@"fileNoteIn", @"eventType",
[NSNumber numberWithInt:note], @"note",
[NSNumber numberWithInt:velocity],@"velocity",
[NSNumber numberWithInt:timeStamp],@"timeStamp",
[NSNumber numberWithInt:position],@"position",
[NSNumber numberWithFloat:percent],@"percentPlayed",
[NSNumber numberWithInt:ticksInLoop],@"ticksInLoop",
nil];
[delegate performSelectorOnMainThread:@selector(midiFileEvent:)
withObject:midiData
waitUntilDone:NO];
[pool release];
}
NSAutoreleasePool是否有可能在触发排队消息之前删除NSDictionary实例?我不是在任何地方消耗池 - 我应该这样做吗?
- (void)simRespondToFileNote:(NSDictionary *)dictionary
{
int velocity = [[dictionary objectForKey:@"velocity"] intValue];
if (velocity == 0){
// noteOff - send it through
[delegate routeUserSimMidiEvent:dictionary];
} else {
float totalPercentCorrect = [dataSource getUserCorrectPercent];
int note = [[dictionary objectForKey:@"note"] intValue];
if (totalPercentCorrect < _userAccuracy){
float lateNoteOnTimeDelay = (dataSource.postTimeHighAccuracy - (dataSource.postTimeHighAccuracy /4)) / 1000.;
float lateNoteOffTimeDelay = lateNoteOnTimeDelay + .1; // revise
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// create noteOff data w/ velocity == 0; timeStamp == 0;
NSDictionary *midiData = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:note], @"note",
[NSNumber numberWithInt:0],@"velocity",
[NSNumber numberWithUnsignedInt:0],@"timeStamp",
nil];
[self performSelector:@selector(simLateResponseToFileNote:) withObject:dictionary afterDelay: lateNoteOnTimeDelay];
[self performSelector:@selector(simLateResponseToFileNote:) withObject:midiData afterDelay: lateNoteOffTimeDelay];
[pool release];
} else {
float lateNoteOnTimeDelay = (dataSource.postTimeLowAccuracy + (dataSource.postTimeLowAccuracy /4)) / 1000.0;
float lateNoteOffTimeDelay = lateNoteOnTimeDelay + .1; // revise
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// create noteOff data w/ velocity == 0; timeStamp == 0;
NSDictionary *midiData =[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:note], @"note",
[NSNumber numberWithInt:0],@"velocity",
nil];
// queue late noteOn
[self performSelector:@selector(simLateResponseToFileNote:) withObject:dictionary afterDelay: lateNoteOnTimeDelay];
// queue late noteOff
[self performSelector:@selector(simLateResponseToFileNote:) withObject:midiData afterDelay: lateNoteOffTimeDelay];
[pool release];
}
}
}
答案 0 :(得分:1)
您正在将midiData
对象创建到自动释放池中,使用performSelector
作为参数执行延迟midiData
,然后耗尽池。你在这里没有看到问题吗?
(释放自动释放池相当于排干它。(阅读文档。)
答案 1 :(得分:1)
在simRespondToFileNote:
中创建临时自动释放池不是很有用,但不应该是一个问题。您拨打performSelector:withObject:afterDelay:
的电话会保留dictionary
,直到被叫方为止。如果forwardFileNoteIn:withVelocity:
在没有自动释放池的线程上,则可能必须创建它,但通常在方法的顶部执行此操作。如果这个线程已经有了一个池,那就没有理由在这里创建。
根据您的描述,我怀疑simLateResponseToFileNote:
阻塞主线程的时间太长。我会在那里寻找瓶颈。