【问题标题】:intermittent EXC_BAD_ACCESS in static audio-analysis function静态音频分析函数中的间歇性 EXC_BAD_ACCESS
【发布时间】:2012-01-30 22:33:05
【问题描述】:

我正在编写一个使用实时音频分析的 iOS 应用。它有一个间歇性的崩溃(大约 5 分钟后,仅在模拟器上。虽然这意味着它不关心运输应用程序,但它确实是开发的痛苦,此外,如果我跟踪它,我晚上会睡得更好崩溃总是发生在同一个地方,在我的音频分析代码中的一个静态函数中:崩溃发生在这里:

struct Tone {
// (other stuff)

// THIS is the problem function:
static bool dbCompare(Tone const& l, Tone const& r) { return l.db < r.db; }
  }
};

还有这里:

Tone const* findTone(double minfreq = 70.0, double maxfreq = 700.0) const {
    if (m_tones.empty()) { m_oldfreq = 0.0; return NULL; }
    double db = std::max_element(m_tones.begin(), m_tones.end(), Tone::dbCompare)->db;
    Tone const* best = NULL;
    double bestscore = 0;
    for (tones_t::const_iterator it = m_tones.begin(); it != m_tones.end(); ++it) {

    // ON THIS LINE. Is my iterator somehow becoming invalid?:
        if (it->db < db - 20.0 || it->freq < minfreq || it->age < Tone::MINAGE) continue;
        if (it->freq > maxfreq) break;
        double score = it->db - std::max(180.0, std::abs(it->freq - 300.0)) / 10.0;
        if (m_oldfreq != 0.0 && std::fabs(it->freq/m_oldfreq - 1.0) < 0.05) score += 10.0;
        if (best && bestscore > score) break;
        best = &*it;
        bestscore = score;
    }
    m_oldfreq = (best ? best->freq : 0.0);
    return best;
}

(好的,下面的这个修复对于@Justin 来说是错误的。我将它留在这里是为了完整性,至少现在是这样)。 为了避免可能传入的任何空指针,我添加了一些检查并尝试进行错误处理:

struct Tone {
    static bool dbCompare(Tone const& l, Tone const& r) {
    try {
      if (&l == NULL || &r == NULL) throw 1;
      return l.db < r.db;
      throw 1;
    }
    catch(int e) {
      NSLog(@"AUDIO ERROR: Pointer invalid. %d", e);
    }
    return 0;
  }
};

没有骰子,它仍然在同一行失败。我误解了try-catch-throw吗?错误只是在进一步备份管道中发生吗?

这段代码来自开源的Rock-Band风格游戏Performous,他们的游戏没有这个问题。 (它也不适用于 iPhone。)所以这给了我希望,我可以消除模拟器崩溃......

EDIT 2 根据@Justin,我正在使用 GuardMalloc。模拟器 5.0 立即崩溃——似乎有 some SO questions about this 但现在我正在运行 4.3 模拟器,它以正常方式给出崩溃,但我不知道如何使用其他任何东西:

#0  0x94f38c97 in malloc_error_break ()
#1  0x94efa4ce in szone_error ()
#2  0x94efc35f in allocate_pages ()
#3  0x94f013cc in allocate_pages_securely ()
#4  0x94f019b8 in szone_malloc_should_clear ()
#5  0x94f0266b in szone_malloc ()
#6  0x00331cc3 in GMmalloc_zone_malloc ()
#7  0x94f38edb in malloc_set_zone_name ()
#8  0x94f394a8 in _malloc_initialize ()
#9  0x94f3986b in malloc ()
#10 0x00002ef0 in start ()
#11 0x00013f1d in std::_List_const_iterator<Tone> std::max_element<std::_List_const_iterator<Tone>, bool (*)(Tone const&, Tone const&)>(std::_List_const_iterator<Tone>, std::_List_const_iterator<Tone>, bool (*)(Tone const&, Tone const&)) at /Developer/of_007_iphone/apps/cwi007/SingXO/SingXO/Pitch/pitch.hh:25
#12 0x000139b2 in Analyzer::findTone(double, double) const ()
#13 0x00011950 in -[AppDelegate timerCallback:] ()
#14 0x00115308 in -[CCTimer update:] ()
#15 0x0011e124 in -[CCScheduler tick:] ()
#16 0x0014993a in -[CCDirectorIOS drawScene] ()
#17 0x0014bda4 in -[CCDirectorDisplayLink mainLoop:] ()
#18 0x007baa88 in CA::Display::DisplayLink::dispatch(unsigned long long, unsigned long long) ()
#19 0x007babcd in CA::Display::EmulatorDisplayLink::callback(__CFRunLoopTimer*, void*) ()
#20 0x019c88c3 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ()
#21 0x019c9e74 in __CFRunLoopDoTimer ()
#22 0x019262c9 in __CFRunLoopRun ()
#23 0x01925840 in CFRunLoopRunSpecific ()
#24 0x01925761 in CFRunLoopRunInMode ()
#25 0x020bb1c4 in GSEventRunModal ()
#26 0x020bb289 in GSEventRun ()
#27 0x00beac93 in UIApplicationMain ()
#28 0x00002fb6 in main ()

我也在控制台中得到了这个:

GuardMalloc[MyApp-723]: *** mmap(size=2097152) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug

哦,当然,这里的函数 NOW 似乎是可能的罪魁祸首:

- (void)timerCallback:(NSTimer *)timer {
  Tone const * tone = audio->analyzer->findTone();
  if (tone && tone->db > kToneMinDB) {
    self.currentPitch = tone->freq;
    self.currentVolume = tone->stabledb;
    self.currentNoteName = [NSString stringWithCString:scale->getNoteStr(tone->freq).c_str() encoding:NSUTF8StringEncoding];
//    NSLog(@"Current Note Name in timerCallback: %@", currentNoteName);
    self.currentNoteFunction = [pitchFilter getPitchFunctionFromPitchName:currentNoteName];
  } else {
    self.currentNoteName = @"--";
    self.currentNoteFunction = -1;
  }

}

我不明白程序如何在没有有效音调的情况下进入if (tone) 块,或者相反,如果音调有效,它会如何崩溃。帮忙?

(这越来越长了。我应该删除其中的一些以解决更集中的问题吗?)

我在想的事情: 1. 这是一个线程问题 ::shudder:: 一个线程正在更改音频数据,而另一个线程正在读取它。 2. timerCallback 函数中的某些东西正在破坏,我不知道,堆栈因为它分配得太频繁了。这个函数被调用了很多,但不是一个极端的数量;每 150 毫秒安排一次。

不知道为什么这些都会是模拟器中的问题,但不是设备上的问题。

【问题讨论】:

    标签: c++ ios audio reference objective-c++


    【解决方案1】:

    C++ 引用永远不能是0/NULL。如果是这样,您已经进入了未定义的领土。如果参数可能是0,您将不得不在执行链中向上移动测试。

    也就是说,dbCompare 唯一格式良好的版本是这样的:

    struct Tone {
        static bool dbCompare(Tone const& l, Tone const& r) {
            return l.db < r.db;
        }
    };
    

    更新

    如果在您迭代时调整了迭代器的大小,您的迭代器将无效——我认为在此实现中不会发生这种情况。您是否正在从另一个线程调整容器的大小?

    另外,请尝试使用 GuardMalloc 运行它 - 它旨在使这些问题对您来说显而易见。通过更快地失败,它将更加本地化(在许多情况下)。

    【讨论】:

    • 这看起来很有希望绕过最新的障碍:stackoverflow.com/questions/7710163/…
    • 好的,立即崩溃看起来像是 iOS 5 模拟器神器。有关 4.3 模拟器上的跟踪,请参见上文。
    • 您是否“在 malloc_error_break 中设置断点进行调试”?它指向什么?您的应用最终会耗尽内存 - GuardMalloc 不会释放,但这通常需要很长时间。
    • 是的,它指向我在OP中添加的timerCallback函数中的代码
    • @ickydog 有太多未定义的内容,我无法猜测下一步。它可能是线程问题(正如我们现在都考虑的那样)。另外,您是否知道 if 这是在您的音频渲染回调中,您不应该锁定? (没有分配,没有锁,没有 objc 消息传递)设备与 sim 是一个完全不同的环境——执行不同是有道理的。如果你的实现没有正确地保护它需要的东西......事情开始泄漏
    【解决方案2】:

    'best = &*it' 行对我来说看起来很奇怪。容器是按引用存储还是按值存储?看起来您可能正在返回临时存储的地址。这可能会导致问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-16
      • 1970-01-01
      • 1970-01-01
      • 2021-08-31
      相关资源
      最近更新 更多