【问题标题】:EXC_BAD_ACCESS in @autoreleasepool from a block来自块的@autoreleasepool 中的 EXC_BAD_ACCESS
【发布时间】:2011-12-17 13:01:49
【问题描述】:

我正在开发一个应用程序,它从加速度计读取数据(每秒 20 个样本),并使用计时器,每 5 秒获取这些数据并使用它们进行计算。 加速度计数据保存在 NSMutableArray (aceleraciones) 中,这是一个属性。然后,当定时器触发时,这个数组被复制到一个使用信号量的新数组中(以便在计算完成时保存新数据)。

我在 main.m 中的 @autoreleasepool 返回语句中得到一个 EXC_BAD_ACCESS(我在那里没有做任何更改)。每次运行应用程序时都会出现此错误,但不是在同一时刻:它出现在一个计时器块执行中,但不是在特定时间(有时是第二次,有时是第五次,依此类推)所以我是很不解。
为了解决它,我几天来一直在搜索和阅读有关内存管理的信息,但我做不到。我猜这是在块中使用变量的错误,但我不确定。

如果有人能对这个主题有所了解,我将不胜感激。

相关代码在这里:

/**
* Function to create the timer
**/
dispatch_source_t creaTimer(uint64_t interval,uint64_t leeway, dispatch_queue_t queue,dispatch_block_t block){
     dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,0,0,queue);    
 if (timer) {
     dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
     dispatch_source_set_event_handler(timer, block);
 }
 return timer;
}


/**
* IBAction which executes when an "Start" button is tapped
**/

-(IBAction) rec{

semaforoArrays = dispatch_semaphore_create(1); //creates semaphore to accessing the saved accelerometer data

__block double  *modulos;
modulos = (double *) malloc(512);       

__block DOUBLE_COMPLEX_SPLIT  A; 

/* Allocate memory for the input operands and check its availability,
 * use the vector version to get 16-byte alignment. */
A.realp = (double *) malloc(1024 * sizeof(double));
A.imagp = (double *) malloc(1024 * sizeof(double));

if (A.realp == NULL || A.imagp == NULL) {
    printf("\nmalloc failed to allocate memory for  the real FFT"
           "section of the sample.\n");
    exit(0);
}

timer = creaTimer(5ull * NSEC_PER_SEC, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0)
                  ,^{ 
   if(numCiclos>0){

     dispatch_semaphore_wait(semaforoArrays, DISPATCH_TIME_FOREVER);

        NSMutableArray *originalArray= [NSMutableArray arrayWithArray:
         self.aceleraciones]; //copy the saved data to manipulate them
        [self.aceleraciones removeAllObjects]; //remove the saved data to put into the array the new data accelerometer will have                            

     dispatch_semaphore_signal(semaforoArrays);


    int tamanno=[originalArray count];

    for(int h=0;h<1024;h++){
      A.realp[h]=0;
      A.imagp[h]=0;
    }  //i reuse the same array (to avoiding allocating it each time)                             

    for(int r=0;r<tamanno;r++){
       A.realp[r]=[[originalArray objectAtIndex:r]doubleValue];
    } //i do that to calculate the Fourier Transform but it doesn´t
       matter in the error (i get it also with this code).

    vDSP_zvabsD(&A, 1, modulos, 1, 512);        
    vDSP_vsqD(modulos,1,modulos,1,512); 

    double sum=0;

    vDSP_sveD(modulos, 1, &sum, 512);

    sum=sum/2.0;
    vDSP_vsdivD(modulos, 1, &sum, modulos, 1, 512);
    }
      numCiclos++;//variable to avoid the execution of the block the first time timer triggers (when it is started)
});    

//until here is the problematic block. I'm sure the error is before this line.



NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
if (motionManager.accelerometerAvailable) {

    motionManager.accelerometerUpdateInterval = 1.0/20.0; 
    label.text = [NSString stringWithFormat:@"Registrando"];

    [motionManager startAccelerometerUpdatesToQueue:queue withHandler:
     ^(CMAccelerometerData *accelerometerData, NSError *error){ 

         if (error) {
             [motionManager stopAccelerometerUpdates]; 
             label.text = [NSString stringWithFormat:
                           @"Error en el acelerometro: %@", error];
         }
         else{
             if(primeraLectura){
                 primeraLectura = FALSE;
                 dispatch_resume(timer); //starts timer             
             }

             dispatch_semaphore_wait(semaforoArrays, DISPATCH_TIME_FOREVER);
             [self.aceleraciones addObject:[NSNumber numberWithDouble:
        sqrt(accelerometerData.acceleration.x*accelerometerData.acceleration.x+ 
        accelerometerData.acceleration.y*accelerometerData.acceleration.y+
        accelerometerData.acceleration.z*accelerometerData.acceleration.z)]];
        //it saves the acceleration module

             dispatch_semaphore_signal(semaforoArrays);          
         }
     }];
}else{
    label.text = @"Este dispositivo no tiene acelerometro.";
}
}

【问题讨论】:

  • 您使用的是手动保留/释放还是 ARC?如果是前者,那么你无疑发布了一些你不应该拥有的东西。可以是任何东西——不一定在您最近更改的代码中。
  • @Hot Licks 我正在使用手动内存管理,但如果我删除块中有关计算的行,运行它时我没有问题。
  • 昨天我做了一个改变,我停止在每个引用上重新创建一个对象,而是缓存它。这实际上导致了您所看到的完全相同的错误。但是错误(当我最终找到它时)不在我的任何更改中,而是在填充对象的代码中——一个项目被过度释放。以前,这些对象的寿命不够长,无法暴露错误。
  • @Hot Licks 命中目标:错误是此代码中的错误 malloc。谢谢你们。正如 Jay 所说,我必须使用 Instruments。我已经意识到了后卫malloc。我在这个愚蠢的事情上花了太多时间,但现在我知道了这个有用的工具。

标签: ios block exc-bad-access


【解决方案1】:

调试这些错误的最佳方法是在 Instruments 中。使用 Zombie 配置文件运行,当您执行导致错误访问的代码时,您将得到一个弹出窗口。点击右下角的箭头可以看到alloc/dealloc列表,一行会显示有问题的代码。

【讨论】:

  • 听起来不错。如何使用僵尸配置文件运行?
  • 从 iOS 6 开始,他们启用了自动引用计数 (ARC),因此您无需手动保留/释放。而且,你不应该得到 EXC_BAD_ACCESS。我强烈建议使用 ARC 重新架构您的应用程序。如果你真的需要,当你运行 Instruments 时,你会看到一个带有一堆你想要的配置文件的图标的屏幕,Zombie 就是其中之一。
  • 如果我有更多时间,我会重新设计我的应用程序。你估计需要多长时间,比如每 1000 行代码?
  • 不知道罗杰,我从来没有做过。也许最好现在完全用 Swift 重写,因为它已经成熟了。我所有的新项目都在里面。
【解决方案2】:

查看motionManager startAccelerometerUpdatesToQueue:。很可能您将queue 参数保存在那里的属性中,然后在您的dealloc 中释放它。但是,当您将 queue 值放入属性时,您并没有保留它。

【讨论】:

  • 是的,queue 变量是这里最有可能的罪魁祸首,因为据我所知,它从未被保留。当你自动释放 NSOperationQueues,在它们上运行东西,但从不将它们保留为实例变量时,奇怪的事情开始发生。
  • 问题(这一次)不是自动释放,而是作为一般规则,¿我应该只使用自动释放来释放从函数返回的对象吗?
  • 通常,只有在返回一个保留的值并且您的函数不是“特殊”函数之一(new...、alloc...、copy. .., et al) 应该返回一个保留值。可能还有其他情况可以使用自动释放来产生良好的效果,但它们是例外。
猜你喜欢
  • 2012-07-26
  • 2012-08-16
  • 1970-01-01
  • 2015-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多