如何修复 objective-c 代码中的内存泄漏问题?

How to fix memory leak issue in objective-c code?

我正在尝试与 iOS 硬件通信,以确定设备是否使用内置扬声器。一切正常,但每当我使用这段代码时,我都会发生内存泄漏。我通过将它放在 objective-c++ 的 .mm 文件中,从我的 C++ 代码中调用它。这是我第一次尝试使用 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;
}
  1. ARC.

来自

I have tried to release some of the objects within the function

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

  1. 自动释放

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

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

不得不写成比较笨拙的

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

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

由于您的代码主要是 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;
    }
}

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

我想这会解决您的问题。