2010-06-01 3 views
0

이 앱의 일부는 TV 프로그램의 출연진으로부터 임의의 비명 소리를 재생하는 "비명 소리"버튼입니다. 인스 트루먼 트에서 메모리 누수를보기 위해 꽤 오랜 시간이 걸렸지 만 가끔씩 (45 초에서 2 분마다) 올라옵니다. 누출은 3.50kb입니다. 몇 시간 동안 깨지 못했습니다. 어떤 도움을 주셔서 감사합니다.iphone : AudioToolbox 도움말 누출 : 여기에 포함 된 스택 추적/코드

Instruments는이 문제가되는 코드 라인 말합니다 :

0 libSystem.B.dylib의 malloc에 ​​
1 libSystem : 아래 스택 트레이스 라인 (9)에 링크 것

[appSoundPlayer play]; 

. B.dylib pthread_create
2 오디오 도구 상자 CAPThread :: Start()
3 AudioToolbox GenericRunLoopThread :: Start()
,4 AudioToolbox AudioQueueNew (BOOL, AudioStreamBasicDescription의 CONST *를 TCACallback의 CONST &, CACallbackTarget의 CONST &, 부호 길이 OpaqueAudioQueue **)
5 AudioToolbox AudioQueueNewOutput
6 AVFoundation allocAudioQueue (AVAudioPlayer * AudioPlayerImpl *)
7 AVFoundation prepareToPlayQueue (AVAudioPlayer * AudioPlayerImpl *)
8 AVFoundation - [AVAudioPlayer prepareToPlay은]
9 비명 퀸즈 - [ScreamViewController 비명 :]/사용자/laptop2/데스크탑/스크림 퀸스 버전/ScreamQueens25/스크림 퀸즈/클래스 /../ ScreamViewController.m을 : (210)
10 CoreFoundation - [N SObject performSelector : withObject : withObject :]
11 UIKit - [UIApplication 액션 (SendAction) : 행 : 행 : forEvent :]
12 UIKit - [UIApplication 액션 (SendAction) : toTarget : fromSender : forEvent :]
13 UIKit - [UIControl 액션 (SendAction) 님 : forEvent :]
14 UIKit - [UIControl (내부) _sendActionsForEvents : withEvent :]
15 UIKit - [UIControl touchesEnded : withEvent :]
16 UIKit - [UIWindow _sendTouchesForEvent :]
17 UIKit - [UIWindow sendEvent : ]
18 UIKit - [UIApplication sendEvent :]
19 [UIApplication _run]
25 UIKit UIApplicationMain
26 스크림 퀸스 메인/사용자/laptop2/화상/스크림 퀸스 - UIKit _UIApplicationHandleEvent
20 GraphicsServices는
21 CoreFoundation에서 CFRunLoopRunSpecific
22 CoreFoundation에서의 CFRunLoopRunInMode
23 GraphicsServices GSEventRunModal
24 UIKit을 PurpleEventCallback 버전/ScreamQueens25/비명 퀸즈/main.m : 14
27 비명 퀸즈 스타트

여기 .H입니다 :

#import <UIKit/UIKit.h> 
#import <AVFoundation/AVFoundation.h> 
#import <MediaPlayer/MediaPlayer.h> 
#import <AudioToolbox/AudioToolbox.h> 
#import <MessageUI/MessageUI.h> 
#import <MessageUI/MFMailComposeViewController.h> 

@interface ScreamViewController : UIViewController <UIApplicationDelegate,  AVAudioPlayerDelegate, MFMailComposeViewControllerDelegate> { 





//AudioPlayer related 
AVAudioPlayer   *appSoundPlayer; 
NSURL     *soundFileURL; 
BOOL     interruptedOnPlayback; 
BOOL     playing; 

//Scream button related 
IBOutlet UIButton  *screamButton; 
int      currentScreamIndex; 
NSString    *currentScream; 
NSMutableArray   *screams; 
NSMutableArray   *personScreaming; 
NSMutableArray   *photoArray; 
int      currentSayingsIndex; 
NSString    *currentButtonSaying; 
NSMutableArray   *funnyButtonSayings; 
IBOutlet UILabel  *funnyButtonSayingsLabel; 
IBOutlet UILabel  *personScreamingField; 
IBOutlet UIImageView *personScreamingImage; 



//Mailing the scream related 
    IBOutlet UILabel  *mailStatusMessage; 
    IBOutlet UIButton  *shareButton; 


} 
//AudioPlayer related 
@property (nonatomic, retain) AVAudioPlayer     *appSoundPlayer; 
@property (nonatomic, retain) NSURL       *soundFileURL; 
@property (readwrite)   BOOL       interruptedOnPlayback; 
@property (readwrite)   BOOL       playing; 

//Scream button related 
@property (nonatomic, retain) UIButton      *screamButton; 
@property (nonatomic, retain) NSMutableArray     *screams; 
@property (nonatomic, retain) NSMutableArray     *personScreaming; 
@property (nonatomic, retain) NSMutableArray     *photoArray; 
@property (nonatomic, retain) UILabel       *personScreamingField; 
@property (nonatomic, retain) UIImageView      *personScreamingImage; 
@property (nonatomic, retain) NSMutableArray     *funnyButtonSayings; 
@property (nonatomic, retain) UILabel       *funnyButtonSayingsLabel; 


//Mailing the scream related 
@property (nonatomic, retain) IBOutlet UILabel     *mailStatusMessage; 
@property (nonatomic, retain) IBOutlet UIButton     *shareButton; 


//Scream Button 
- (IBAction) scream:     (id) sender; 

//Mail the scream 
- (IBAction) showPicker: (id)sender; 
- (void)displayComposerSheet; 
- (void)launchMailAppOnDevice; 


@end 

여기의 상단입니다.남 :

#import "ScreamViewController.h" 

//top of code has Audio session callback function for responding to audio route changes (from Apple's code), then my code continues... 

@implementation ScreamViewController 

@synthesize appSoundPlayer;    // AVAudioPlayer object for playing the selected scream 
@synthesize soundFileURL;    // Path to the scream 
@synthesize interruptedOnPlayback;  // Was application interrupted during audio playback 
@synthesize playing;     // Track playing/not playing state 


@synthesize screamButton;    //Press this button, girls scream. 
@synthesize screams;     //Mutable array holding strings pointing to sound files of screams. 
@synthesize personScreaming;   //Mutable array tracking the person doing the screaming 
@synthesize photoArray;     //Mutable array holding strings pointing to photos of screaming girls 
@synthesize personScreamingField;  //Field updates to announce which girl is screaming. 
@synthesize personScreamingImage;  //Updates to show image of the screamer. 
@synthesize funnyButtonSayings;   //Mutable array holding the sayings 
@synthesize funnyButtonSayingsLabel; //Label that updates with the funnyButtonSayings 


@synthesize mailStatusMessage;   //did the email go out 
@synthesize shareButton;    //share scream via email 

다음 줄은 잘못된 코드 블록을 시작 : 지금이 글을 읽고에 대한

- (void)dealloc { 
    [appSoundPlayer stop]; 
    [appSoundPlayer release], appSoundPlayer = nil; 
    [screamButton release], screamButton = nil; 
    [mailStatusMessage release], mailStatusMessage = nil; 
    [personScreamingField release], personScreamingField = nil; 
    [personScreamingImage release], personScreamingImage = nil; 
    [funnyButtonSayings release], funnyButtonSayings = nil; 
    [funnyButtonSayingsLabel release], funnyButtonSayingsLabel = nil; 
    [screams release], screams = nil; 
    [personScreaming release], personScreaming = nil; 
    [soundFileURL    release]; 

    [super dealloc]; 
} 


@end 

정말 고마워요 :

- (IBAction) scream: (id) sender 
{ 
    //Play a click sound effect 
    SystemSoundID soundID; 
    NSString *sfxPath = [[NSBundle mainBundle] 
         pathForResource:@"aClick" ofType:@"caf"];  

    AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:sfxPath],&soundID); 
    AudioServicesPlaySystemSound (soundID); 


    // Because someone may slam the scream button over and over, 
    //must stop current sound, then begin next 
    if ([self appSoundPlayer] != nil) 
    { 
     [[self appSoundPlayer] setDelegate:nil]; 
     [[self appSoundPlayer] stop]; 
     [self setAppSoundPlayer: nil]; 

    } 


    //after selecting a random index in the array (did that in View Did Load), 
    //we move to the next scream on each click. 

    //First check... 
    //Are we past the end of the array? 

    if (currentScreamIndex == [screams count]) 
    { 
     currentScreamIndex = 0; 
    } 


    //Get the string at the index in the personScreaming array 

    currentScream = [screams objectAtIndex: currentScreamIndex]; 


    //Get the string at the index in the personScreaming array 
    NSString *screamer = [personScreaming objectAtIndex:currentScreamIndex]; 

    //Log the string to the console 
    NSLog (@"playing scream: %@", screamer); 

    // Display the string in the personScreamingField field 
    NSString *listScreamer = [NSString stringWithFormat:@"scream by: %@", screamer]; 

    [personScreamingField setText:listScreamer]; 


    // Gets the file system path to the scream to play. 
    NSString *soundFilePath = [[NSBundle mainBundle] pathForResource: currentScream 
                   ofType:    @"caf"]; 

    // Converts the sound's file path to an NSURL object 
    NSURL *newURL = [[NSURL alloc] initFileURLWithPath: soundFilePath]; 
    self.soundFileURL = newURL; 
    [newURL release]; 
    [[AVAudioSession sharedInstance] setDelegate: self]; 
    [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: nil]; 

    // Registers the audio route change listener callback function 
    AudioSessionAddPropertyListener (
            kAudioSessionProperty_AudioRouteChange, 
            audioRouteChangeListenerCallback, 
            self 
            ); 

    // Activates the audio session. 

    NSError *activationError = nil; 
    [[AVAudioSession sharedInstance] setActive: YES error: &activationError]; 

    // Instantiates the AVAudioPlayer object, initializing it with the sound 
    AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: soundFileURL error: nil]; 

    //Error check and continue 
    if (newPlayer != nil) 
    { 
     self.appSoundPlayer = newPlayer; 
     [newPlayer release]; 
     [appSoundPlayer prepareToPlay]; 
     [appSoundPlayer setVolume: 1.0]; 
     [appSoundPlayer setDelegate:self]; 
     //NEXT LINE IS FLAGGED BY INSTRUMENTS AS LEAKY 
     [appSoundPlayer play]; 
     playing = YES; 



     //Get the string at the index in the photoArray array 
     NSString *screamerPic = [photoArray objectAtIndex:currentScreamIndex]; 

     //Log the string to the console 
     NSLog (@"displaying photo: %@", screamerPic); 

     // Display the image of the person screaming 
     personScreamingImage.image = [UIImage imageNamed:screamerPic]; 

     //show the share button 
     shareButton.hidden = NO; 

     mailStatusMessage.hidden = NO; 
     mailStatusMessage.text = @"share!"; 



     //Get the string at the index in the funnySayings array 
     currentSayingsIndex = random() % [funnyButtonSayings count]; 
     currentButtonSaying = [funnyButtonSayings objectAtIndex: currentSayingsIndex]; 

     NSString *theSaying = [funnyButtonSayings objectAtIndex:currentSayingsIndex]; 
     [funnyButtonSayingsLabel setText: theSaying]; 

     currentScreamIndex++; 



    } 
} 

여기 내의 dealloc입니다! 모든 의견을 감사드립니다.

답변

3

이것은 누수 도구의 붉은 청어입니다. dev 포럼 에서이 게시물을 참조하십시오 : https://devforums.apple.com/message/119423#119423 AVAudioPlayer 내 구현에서 누출 도구에서 동일한 누수를 "감지"하고 내 코드가 정확하다는 것을 확신합니다 (주로 간단하기 때문에). 실제 전문가의 논평은 다음과 같습니다. 그는 [NSThread start]에서 3.5k를 감지했으며 3.5k [CAPThread :: Start()]를 사용했습니다. 그러나 우리는 같은 보트에 있다고 생각합니다 :

"문제는 3.5K 기본적으로 커널이 스레드를 추적하는 데 필요한 데이터 구조입니다.이 데이터 구조는 결국 해제되지만 일단 스레드가 종료되면 더 이상 프로세스 공간 (커널에만 있음)에 대한 참조가 없습니다. "

도움이 되었기를 바랍니다.

+0

Rab, 고마워요! 당신의 추측이 내가 가진 2 가지 문제 중 일부였던 것 같습니다. 나는 나의 아울렛 2의 유지 수, 현재 컨트롤러와 수퍼했다 몰랐어요. 뷰가 "멈춰"메모리가 부족하다는 경고를 받았을 때 메모리가 누수되고 뷰가 언로드되지만 올바르게 할당이 해제되지 않았습니다. 내 viewDidUnload 및 dealloc을 변경하면 다음과 같이 표시됩니다. - (void) viewDidUnload { \t [appSoundPlayer release], appSoundPlayer release = [super viewDidUnload]; } - (void) dealloc { \t [appSoundPlayer release]; \t [super dealloc]; } –

+0

다행히 해결되었습니다. – Rab