【问题标题】:Memory management with NSThread使用 NSThread 进行内存管理
【发布时间】:2011-09-27 09:14:28
【问题描述】:

我有一个应用程序需要用莫尔斯电码连续发出一个单词。我通过创建一个 NSThread 并使用“while 循环”在选择器内运行一些代码来做到这一点。代码如下:

@implementation MorseCode


-(void)startContinuousMorseBroadcast:(NSString *)words{
    if (!(threadIsOn)) {

    threadIsOn = YES; s

    myThread = [[NSThread alloc] initWithTarget:self selector:@selector(threadSelector:) object:words];

    [myThread start];

}

if (morseIsOn) {
    morseIsOn = NO;
}
else{
    morseIsOn = YES;
}


   }

-(void)threadSelector:(NSString *)words{  

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

while (![myThread isCancelled]) {

//    ///it Does some code here


} //end While


NSLog(@"Cleaning the pool");
    [pool drain];
}


@end

退出应用程序时(用户按下按钮),在 applicationDidEnterBackground 中执行以下选择器:

-(void)cleanUpMorseObject{ //this is defined in the MorseCode class, same as threadSelector
    if (threadIsOn) {

        NSLog(@"cleanUpMorseObject, threadIsOn");
        threadIsOn = NO;
        morseIsOn = NO;

        [myThread cancel];
        [myThread release];

    }
}

应用程序正确响应事件,我用 nslog 进行了检查。 然后调用 [MorseCode release]。 代码如下所示:

-(void)applicationDidEnterBackground{ //this happens in the ViewController
[theMorse cleanUpMorseObject]; //theMorse is an instance of MorseCode
[theMorse release];
}

问题:虽然我调用[myThread release]然后[theMorse release] theMorse的retainCount仍然在0以上(它不调用dealloc )。

Leaks Instrument 并没有说我有泄漏,但如果我打开和关闭应用程序大约 10 次,Iphone 最终会重置。同样在调试器中,我最终看到“收到内存警告。级别=2”。

另外,我从来没有在池耗尽之前看到 NSLog……

应用程序不在后台运行。 有任何想法吗?谢谢

【问题讨论】:

    标签: iphone objective-c memory-management nsthread


    【解决方案1】:

    您确实应该安排在 RunLoop 上发送消息,最简单的方法可能是安排一个计时器(无限重复,以及像 FLT_EPSILON 或类似的短重复周期),而不是为此使用线程。

    使用线程很复杂,每个人都应该避免它(正如 Apple 在其并发编程指南中所述,并且正如大多数文档所说,“线程是邪恶的”;))。

    那是因为多线程是一个庞大而复杂的主题,它需要同步、资源保护、意识到死锁、临界区等、良好和适应的内存管理等等。一般来说,如果你需要在后台做一些事情:

    • 如果可用,请使用现有机制(例如某些操作的异步实现以及通过委托方法或通知发出信号)
    • 使用performInBackground:之类的方法
    • 使用 NSOperationQueues
    • 使用 GCD
    • 只有在万不得已的情况下,如果没有其他选择(或对于非常具体的情况),请使用NSThread

    这将为您避免很多问题,因为所有其他更高级别的 API 将为您处理很多事情。


    此外,像您这样使用线程来执行此任务可能会使用更多的 CPU(可能会很快达到 100% 的使用率),因为任务调度程序将没有任何时间(这也是为什么即使 GCD 也需要像 NSThreads 这样处理所有事情要好得多,如果你不需要强 RT 约束,在 RunLoop 中调度发送对 CPU 来说甚至更好)

    【讨论】:

      【解决方案2】:

      首先,retainCount 永远不能返回 0。这是一个无用的方法。不要叫它。

      其次,泄漏只检测不再引用的对象。如果线程仍在运行,则不会泄漏。

      最后,当您调用cancel 时,线程不会停止。它只是设置一个标志,您必须通过isCancelled 检查它是否该停止线程中的工作。你这样做了吗?


      好的——简单的回答。下一个?尝试构建和分析。然后使用分配工具并打开引用计数跟踪。那就看看是什么叫retain 加班。

      【讨论】:

      • 感谢您提供第一和第二信息,很高兴知道。我知道“取消”是做什么的。我的代码使用 while ![myThread isCancelled] 检查
      【解决方案3】:

      我决定放弃 NSThread 类并使用另一种方法:

      -(void)playSOSMorse{
      
          if ([myTimer isValid]) {
      
              [myTimer invalidate];
              [myTimer release];
              myTimer = nil;
          }
      
              myTimer = [[NSTimer scheduledTimerWithTimeInterval:0.001
                                                          target:self
                                                        selector:@selector(tymerSelector)
                                                        userInfo:nil
                                                         repeats:NO] retain];
          //the timer calls a selector that performs a selector in background
      
      }
      
      -(void)tymerSelector{
      
          [self performSelectorInBackground:@selector(threadSelector2) withObject:nil];  
      }
      
      -(void)threadSelector2   {
      
      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
      
      //some code here
      
       [pool drain];
      
      //calls another selector on the main thread to see if it needs to fire the timer again and restart the cycle
       [self performSelectorOnMainThread:@selector(selectorOnMainThread) withObject:nil waitUntilDone:NO];
      
      }
      
      -(void)selectorOnMainThread{
              [myTimer invalidate];
              [myTimer release];
      
      
          myTimer = nil;
      
      
          if (morseIsOn) { //this is a boolean that if it is true (YES) calls the timer again
      
              [self playSOSMorse];  
      
          }
      
      }
      

      我希望这对某人有帮助:) 谢谢

      【讨论】:

        猜你喜欢
        • 2011-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多