Память не будет очищаться из фонового потока в Swift

#ios #swift #memory #dispatch-queue

Вопрос:

У меня есть приложение, которое постоянно считывает данные с моего сервера и обновляет данные в пользовательском интерфейсе. Он извлекает довольно много данных, создает некоторые структуры данных, а затем передает информацию в пользовательский интерфейс. Приведенный ниже код показывает, как я собираю данные:

 class Server {
    private var units: [Unit] = []

    ...

    init {
        // I pull data from a firebase realtime database here using the observe method
        // which triggers the callback everytime the data changes
        // 'data' is a big dictionary of dictionarys  which will be sorted into objects
        FirebaseDatabaseHandler.getServerInfo(serverAddress: address, callback: { data in

            // Because its a lot of data sorting it is hefty so I do this on a background thread
            // 'updateQueue' is a single static DispatchQueue that I create in AppDelegate for now
            AppDelegate.updateQueue.async {

                // here I create an array of data objects using the JSON I pulled from firebase
                // then I set the "units" variable of this object and call my update callback
                // which triggers a UI update on the main thread
                if let unitData = (data?["units"] as? [String:Any]) {
                    var unitsArray = [Unit]()
            
                    for key in unitData.keys {
                        unitsArray.append(Unit(address: key.base64Decode, data: unitData[key] as! [String:Any]))
                    }
            
                    self.units = unitsArray
                    self.updateCallback()
                }
            } 
       })
   }
   
   ...
 

Приведенный выше код работает нормально, однако память постоянно увеличивается и не освобождается должным образом, после запуска в течение ~ 10-20 минут приложение создает до 2 ГБ памяти и выходит из строя из-за нехватки памяти.

Если я избавлюсь от AppDelegate.updateQueue.async { } и просто позволю этому коду выполняться в основном потоке, память ДЕЙСТВИТЕЛЬНО очищается, и сбоев нет, память остается около 50-200 МБ, однако, если я это сделаю, пользовательский интерфейс, по сути, навсегда зависает из-за того, сколько обработки происходит в основном потоке

Я пытался использовать отладчик для просмотра размера моего units массива и моего Server объекта, но ни один из них не увеличивается в размерах независимо от того, как долго работает приложение.

Могу ли я что-нибудь сделать для отладки этого или по какой-либо причине, по которой память не будет очищаться при запуске из фонового потока?

Комментарии:

1. Вы пробовали использовать инструменты для отладки поведения памяти вашего приложения? ( developer.apple.com/videos/play/wwdc2019/411 )

2. Я пытаюсь создать вашу проблему с помощью примера проекта, работающего в глобальном фоновом потоке, по-прежнему удаляю выделение, не могу воспроизвести вашу проблему

3. @AchmadJP Я посмотрю, смогу ли я придумать простой способ воспроизведения… возможно, я все равно найду проблему при этом: P спасибо за усилия

Ответ №1:

Добавить [слабый self]:

 FirebaseDatabaseHandler.getServerInfo(serverAddress: address, callback: {[weak self] data in

    AppDelegate.updateQueue.async { [weak self] in
 

Обратите внимание, что вам нужно будет внести еще некоторые коррективы, потому что self станет необязательным.

Комментарии:

1. Просто попробовал это, похоже, все еще возникает та же проблема — попытается создать простой способ ее воспроизведения