2011-12-05 49 views
0

我試圖追蹤我正在開發的應用程序的凍結問題。我可能會在NSAutoreleasePool的最後端,並搞砸了。使用NSAutoreleasePool凍結

該應用正在播放MIDI文件。如果我註釋掉下面使用NSAutoreleasePool的代碼「simRespondToFileNote」,它不會凍結。如果我讓代碼運行,它將凍結在看起來隨機的點崩潰日誌/控制檯輸出似乎並沒有表明問題發生的地方。

下面是程序流:

  1. 我使用的低音MIDI LIB(C LIB);它在它自己的線程中播放MIDI文件。

  2. 當發生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]; 

}

  1. 從消息發送到使用所述的NSDictionary實例作爲PARAM另一個對象委託。該對象要麼將NSDictionary實例立即發送到另一個對象,要麼將其排隊以便在短暫延遲後使用(使用performSelector:afterDelay:)。

在觸發排隊消息之前,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]; 

    } 
} 

}

回答

1

你的臨時自動釋放池的創作simRespondToFileNote:是不是很有用,但不應該是一個問題。您致電performSelector:withObject:afterDelay:將保留dictionary,直到其呼叫。如果forwardFileNoteIn:withVelocity:位於還沒有自動釋放池的線程上,則可能需要創建它,但通常在方法的頂部執行此操作。如果這個線程已經有一個池,那麼沒有理由在這裏創建。

從您的描述中,我會懷疑simLateResponseToFileNote:阻塞主線程太長。我會在那裏尋找瓶頸。

+0

謝謝。我在'simRespondToFileNote:'中取出了autorelease池,現在明白這是多餘的。儘管如此,仍然凍結。我想知道如果我造成(不知道這裏的正確術語)太大的堆棧(?)通過重用原始詞典(來自'forwardFileNoteIn:'),因爲我通過多個方法調用將它作爲參數傳遞。 –

+0

傳遞字典非常便宜。 ObjC分配堆上的所有對象,只傳遞指針。所以這不是字典的傳遞。我會通過儀器運行這個程序,看看掛起過程中碰到什麼CPU。 –

+0

謝謝。字典似乎走的路 - 很高興它不是一個昂貴的方法。有沒有一種方法可以確定一個特定的字典使用多少內存: - 像加入條目的內存使用加上?字典開銷?我通過儀器 - 內存,分配,殭屍等運行我的項目。我沒有看到任何泄漏或問題,似乎是一個問題(我可能不知道什麼構成問題.. ;-) –

1

您建立midiData對象放到自動釋放池,使用midiData作爲參數做一個延遲performSelector,然後排水池。你在這裏沒有看到問題嗎?

(釋放一個自動釋放池,相當於排放了。(閱讀文檔。))

+1

'performSelector'將保留傳遞的對象和接收者。 –

+0

謝謝。是的,我現在明白了。 –