【问题标题】:How to fix memory leak issue in objective-c code?如何解决objective-c代码中的内存泄漏问题?
【发布时间】:2019-06-07 08:53:54
【问题描述】:

我正在尝试与 iOS 硬件进行通信,以查看设备是否使用内置扬声器。一切正常,但是每当我使用此代码时,都会出现内存泄漏。我从我的 C++ 代码中调用它,方法是将它放在一个用于 Objective-C++ 的 .mm 文件中。这是我第一次尝试使用objective-c,所以我很难知道泄漏可能来自哪里。我什至不知道这段代码是否有问题,我从堆栈溢出或iOS API的某些东西中稍微调整了一下?这段代码也被非常频繁地调用。

根据我对objective-c的一点了解,我试图释放函数中的一些对象,但这会在音频驱动程序更改设置(采样率等)时导致问题并导致崩溃。

bool Headphones::isHeadsetPluggedIn() {
    AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute];
    for (AVAudioSessionPortDescription* desc in [route outputs]) {
        if ([[desc portType] isEqualToString:AVAudioSessionPortBuiltInSpeaker])
        {
            return NO;
        }
    }
    return YES;
}

【问题讨论】:

    标签: c++ objective-c memory-management memory-leaks objective-c++


    【解决方案1】:
    1. ARC.

    来自

    我已经尝试释放函数内的一些对象

    我推断您的 Objective-C++ 编译单元中有 ARC(自动引用计数)已禁用。除非您有充分的理由,否则这可能不是一个好主意,因为 ARC 大大减少了泄漏的机会。我认为这不是您问题的根源,因为乍一看我无法发现任何可能返回保留对象的方法。

    1. 自动释放

    您的代码调用的大量 Objective-C 方法的返回类型被标记或推断为自动释放。这解决了没有 ARC 的问题,保留返回的对象意味着调用者不能简单地在另一个表达式中使用方法调用表达式,而是总是必须将结果分配给变量以便能够随后释放它,如果不保留它,可能会导致释放后使用的情况。例如,

        AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute];
    

    应该写成比较尴尬的

        AVAudioSession* session = [AVAudioSession sharedInstance];
        AVAudioSessionRouteDescription* route = [session currentRoute];
        [session release];
    

    因此,自动释放。这意味着返回的对象 被保留,但被放置在当前的自动释放池中。这本质上是一堆对象指针,稍后会分批发布。批次由@autoreleasepool 块描述。在 Objective-C 代码中,you usually only need to place these blocks explicitly in loops which operate on very large or very many objects 是为了避免内存使用膨胀,但 runloop 和其他事件源会隐式创建一个池,该池会在事件处理程序返回时被清除。

    由于您的代码主要是 C++,我怀疑您没有足够频繁地使用这种隐式池,尤其是在您使用传统游戏循环的情况下。解决方案是将您的函数包装在一个池中:

    bool Headphones::isHeadsetPluggedIn() {
        @autoreleasepool
        {
            AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute];
            for (AVAudioSessionPortDescription* desc in [route outputs]) {
                if ([[desc portType] isEqualToString:AVAudioSessionPortBuiltInSpeaker])
                {
                    return NO;
                }
            }
            return YES;
        }
    }
    

    这意味着在此函数执行期间标记为自动释放的任何对象都将在返回时释放。

    我怀疑这会解决你的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-23
      • 2012-08-19
      • 2011-07-29
      • 1970-01-01
      • 1970-01-01
      • 2011-05-28
      • 1970-01-01
      相关资源
      最近更新 更多