【问题标题】:Can somebody give me a hand about this stacktrace in iPhone app?有人可以帮我了解一下 iPhone 应用程序中的这个堆栈跟踪吗?
【发布时间】:2010-11-17 22:35:39
【问题描述】:
Program received signal:  “EXC_BAD_ACCESS”.
(gdb) bt
#0  0x30011940 in objc_msgSend ()
#1  0x30235f24 in CFRelease ()
#2  0x308f497c in -[UIImage dealloc] ()
#3  0x30236b78 in -[NSObject release] ()
#4  0x30a002a0 in FlushNamedImage ()
#5  0x30250a26 in CFDictionaryApplyFunction ()
#6  0x30a001a4 in _UISharedImageFlushAll ()
#7  0x30a00738 in +[UIImage(UIImageInternal) _flushCacheOnMemoryWarning:] ()
#8  0x3054dc80 in _nsnote_callback ()
#9  0x3024ea58 in _CFXNotificationPostNotification ()
#10 0x3054b85a in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#11 0x3054dbc0 in -[NSNotificationCenter postNotificationName:object:] ()
#12 0x30a00710 in -[UIApplication _performMemoryWarning] ()
#13 0x30a006a8 in -[UIApplication _receivedMemoryNotification] ()
#14 0x30a005d8 in _memoryStatusChanged ()
#15 0x30217416 in __CFNotificationCenterDarwinCallBack ()
#16 0x3020d0b0 in __CFMachPortPerform ()
#17 0x30254a76 in CFRunLoopRunSpecific ()
#18 0x3025416a in CFRunLoopRunInMode ()
#19 0x320452a4 in GSEventRunModal ()
#20 0x308f037c in -[UIApplication _run] ()
#21 0x308eea94 in UIApplicationMain ()
#22 0x00002096 in main (argc=1, argv=0x2ffff514)

目前我的程序中有一个非常奇怪的错误。有时会发生,有时不会。但这里是正在发生的事情的摘要:

程序启动时:

  • 已保存的数据(只是一个由 13 个元素组成的简短 plist)如果存在则加载。
  • 一个包含 1014 个字符串的巨大 plist 被加载到 NSMutableDictionary 中。
  • 另一个包含 78 个字符串的 plist 被加载到 NSArray 中。
  • 播放 .mp4 电影。

该错误发生在 OpenGL ES View 正在被移除并且用户将要查看 NSMutableDictionary 中 1014 个字符串中的一个字符串的部分。

模拟器中永远不会出现此错误。它只发生在 iPhone 上,有时运行良好,但有时会崩溃。

但是,在阅读了堆栈跟踪之后,我在其中看到了 CFDictionaryApplyFunction,所以我认为这可能是可能的原因之一。是不是因为在模拟器上,它读取东西的速度非常快,以至于 plist 中的整个字典都会立即加载,而在设备上,它读取速度较慢?老实说,我不知道这本词典是如何工作的。它是瞬间读取所有 1014 个字符串,还是使用其他一些线程缓慢读取?请指教。谢谢。

【问题讨论】:

  • 在 iPhone 上,内存相对较小,因此您更有可能收到内存警告。在模拟器上,尝试模拟内存警告(在Hardware 菜单项下找到选项)。

标签: iphone stack-trace callstack exc-bad-access


【解决方案1】:

您可能需要设置NSZombiesEnabled 环境变量。这样,您的应用程序在访问已发布的对象时不会因EXC_BAD_ACCESS 而崩溃,而是将信息性消息记录到您的控制台。 This blog post 很好地解释了发生了什么以及如何在 XCode 中进行设置。无论如何,永远不要忘记在生产版本中禁用此选项,否则您的对象将永远不会被释放!

【讨论】:

    【解决方案2】:

    当您收到EXC_BAD_ACCESS 时,通常意味着您正在尝试调用不存在的对象上的方法——可能是因为它已被释放。

    大约在跟踪的一半,有一些内存警告调用,例如:

    #12 0x30a00710 in -[UIApplication _performMemoryWarning] ()
    

    这使得您的代码看起来没有直接导致崩溃,而是在内存不足时发出系统通知。

    接近第 0 帧,它似乎正在尝试清除 UIImage 对象的缓存,这似乎是错误的访问。

    基于此,一种猜测是您正在分配一个指向便利构造函数的自动释放返回值的指针;然后该对象被自动释放,您可能认为这很好,因为您不直接使用图像,但是内存警告会尝试访问它。例如:

    @interface MyClass {
      UIImage* myImage;
    }
    // ...
    - (id) init {  /* the usual stuff */
      myImage = [UIImage imageNamed:@"bob_the.png"];
      return self;
    }
    

    在此示例中,即使您在myImage 上设置了保留属性,除非您通过self.myImage 设置值,否则您实际上并没有保留图像。所以,在这个调用之后不久,图像就被释放了,你得到了一个指向无人区的指针。

    没有看到代码,我无法知道实际情况是否如此,但这是一种很容易犯的错误。

    这些相关问题提供了类似崩溃的提示:EXC_BAD_ACCESS调试question 1question 2

    最后,如果这些都没有帮助,我建议您找到问题的最小重现。要做到这一点,最困难的方法是复制你的代码,剪掉一半,看看错误是否仍然存在,然后重复,直到你找到能重现错误的最小代码。从那里进行调试通常要容易得多(并且也可以作为 stackoverflow 问题发布!)如果您知道简单的方法,请告诉我。

    【讨论】:

    • 你也可以这样赋值:myImage = [[UIImage imageNamed:@"bob_the.png"] retain].
    • 按照你说的,这部分可能是问题的原因?下面这段代码在 UIImageView 的一个子类的方法中。 NSString* st; st = [[NSString alloc] initWithFormat:@"sc%d.png", selectedNumber]; self.image = [UIImage imageNamed:st]; [st 发布];基本上我像这样设置了 UIImageView 的图像。有没有可能是这个原因?
    • 请允许我再测试一下,看看它不会导致更多错误。现在,我的 UIImageView 子类中有一个保留的 UIImage*。非常感谢你,泰勒先生。 (作为学生鞠躬)
    • unknownthreat - 如果 self.image 中的图像是一个保留属性,那么该代码是可以的(不是错误的),因为“self.image = X”为您隐式调用保留。检查您在将 image 声明为成员变量的头文件中 @property 之后是否有“保留”。 Daniel Rinser(此处的另一个答案)提供了很好的建议,解释了如何设置 NSZombiesEnabled 变量以帮助获取更多调试信息。
    • 我有一个坏消息。似乎错误再次发生。但是在我从 XCode 在设备上运行我的应用程序后,错误停止发生。但我认为主要问题肯定是 UIImage。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-28
    • 2010-09-17
    • 1970-01-01
    • 2017-08-13
    • 1970-01-01
    相关资源
    最近更新 更多