Как исправить проблему утечки памяти в коде target-c? - PullRequest
1 голос
/ 07 июня 2019

Я пытаюсь установить связь с оборудованием iOS, чтобы определить, использует ли устройство встроенные динамики или нет. Все работает нормально, но всякий раз, когда я использую этот код, я получаю утечку памяти. Я вызываю это из своего кода C ++, помещая это в файл .mm для target-c ++. Я впервые пытаюсь использовать цель-c, поэтому я изо всех сил пытаюсь понять, откуда может исходить утечка. Я даже не знаю, если это проблема с этим кодом, который я немного адаптировал от переполнения стека или что-то с iOS API? Этот код также вызывается очень часто.

Из моего небольшого знания о target-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 Ответ

1 голос
/ 07 июня 2019
  1. ARC.

С

Я пытался освободить некоторые объекты в функции

Я сделал вывод, что у вас ARC (автоматический подсчет ссылок) отключен в вашем модуле компиляции Objective-C ++.Если у вас нет веских причин, это, вероятно, не очень хорошая идея, поскольку ARC резко снижает вероятность утечек.Я не думаю, что это является источником вашей проблемы, так как я не могу определить какие-либо методы, которые могут вернуть удерживаемые объекты на первый взгляд.

Авто-релиз

Значительное число методов Objective-C, которые вызывает ваш код, имеют типы возврата, помеченные или выведенные как авто-релиз.Это решает проблему, заключающуюся в том, что без ARC сохранение возвращаемых объектов означало бы, что вызывающая сторона не могла бы просто использовать выражение вызова метода в другом выражении, но всегда должна была бы присваивать результат переменной, чтобы иметь возможность впоследствии ее освободить,без сохранения может привести к ситуации использования после освобождения.Например,

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

должно быть записано как довольно неудобное

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

Следовательно, авто-релиз.Это означает, что возвращенный объект сохранен, но помещен в текущий автоматический выпуск пул .По сути, это набор указателей на объекты, который позже выпускается партиями.Партии размечены @autoreleasepool блоками.В коде Objective-C обычно вам нужно только явно поместить эти блоки в циклы, которые работают с очень большими или очень многими объектами , чтобы избежать раздувания в памяти, но 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;
    }
}

Это означает, что любые объекты, помеченные для автоматического выпуска во время выполнения этой функции, будут возвращены после возврата.

Я подозреваю, что это решитваша проблема.

...