2015-10-31 5 views
3

В моем приложении (приложение OS X) я отправляю около 5000 URL-запросов за короткий промежуток времени, чтобы получить объекты JSON с сервера. Я отправляю 50 запросов одновременно, дожидаюсь их завершения, а затем отправляю еще одну партию из 50. Но у меня возникают проблемы с управлением памятью ...NSURLSession - высокое использование памяти

К тому времени, когда все запросы завершены (~ 2 минут), мое приложение увеличило объем использования памяти примерно на 250 МБ, и эта память никогда не освобождается. Я использую NSURLSession/dataTaskWithURL для извлечения данных, и для устранения неполадок я удалил ВСЕ код из обработчика завершения - он просто запускает запрос и отбрасывает ответ. Вот пример:

func fetchData() { 
    let config = NSURLSessionConfiguration.ephemeralSessionConfiguration() 
    // Also tried .defaultSessionConfiguration() 
    config.URLCache = nil 
    config.HTTPCookieAcceptPolicy = .Never 
    config.HTTPCookieStorage = nil 
    let session = NSURLSession(configuration: config) 

    let query = session.dataTaskWithURL(myURL) { (data, response, error) -> Void in 
     session.invalidateAndCancel() 
     // Normally call a completion handler here too 
    } 
    query.resume() 
} 

Обратите внимание, что я отключить все кэш и куки, а также вызова invalidateAndCancel() когда запрос завершен. Я также пробовал использовать стандарт sharedSession(), но ничто из этого не имеет значения - использование памяти всегда быстро поднимается и постоянно остается навсегда.

Это большая проблема, потому что моему приложению необходимо периодически отправлять эти запросы, и память с каждым циклом поднимается выше, что в конечном итоге достигает нескольких ГБ ОЗУ. Следует также отметить, что моя программа замедляет сканирование, как только использование памяти достигло этой точки.

Кто-нибудь знает, почему NSURLSession может содержать столько памяти? Профилирование с помощью инструментов не выявляет утечек памяти, поэтому я довольно сильно обеспокоен здесь. Любая помощь или предложения были бы весьма признательны.

+0

Дополнительная информация о том, почему вам нужно 5000 сеансов? Похоже, вы работаете против iOS здесь, это безумное большое число? – Ben

+0

@Ben Это приложение для Mac, а не приложение для iOS. В принципе, он работает 24/7 и выполняет анализ на огромные объемы данных. Это много запросов, но, естественно, у машины есть подключение к Интернету для его обработки. Я должен также упомянуть, что я пытался повторить использование сеансов, а не создавать новый для каждого запроса, но безрезультатно. – hundley

ответ

0

Вы пробовали настройки

Config = nil 
Query = nil 
Session = nil 
[session finishTasksAndInvalidate] 

В конце концов? Но лично я был бы больше обеспокоен тем, почему вам нужно сделать 5000 запросов? Похоже, плохой дизайн мне ...

+0

Я дал ему попробовать, за исключением запроса, потому что он не может быть установлен в нуль внутри собственного обработчика завершения. Но он по-прежнему сохранил тот же объем памяти. В ответ на этот проект я расскажу об этом также и для будущих читателей: это приложение Mac, которое работает 24 часа в сутки 7 дней, собирает большие объемы данных и выполняет различные типы анализа по этим данным. Данные поступают из нескольких источников, причем не все из них поддерживают выборку партии, поэтому (к сожалению) требуется 5000 запросов. – hundley

+0

Вы пытались установить их на нуль после запроса. Вместо использования внутри блока? – Ben

+0

Да, я попробовал установить их на нуль после query.resume(), а также - никакой разницы. – hundley

2

Две вещи:

  1. Поскольку вы используете NSURLSession, убедитесь, что вы не инстанцировании новый для каждого из этих 5000 запросов. Вызывается, а затем повторно используется. Возможно, попробуйте вместо этого использовать NSURLSession.sharedSession().

    Я видел скромное потребление памяти на сессию, и если у вас есть необыкновенное количество сеансов, он может добавить до

  2. Вы говорите, что вы запускали инструменты для поиска утечек. В настоящее время вы редко найдете что-то столь же вопиющее, как это. Но вы также должны искать сильные опорные циклы и т.п., как путем анализа распределения или поколений между двумя точками во время и определить каких счета за 250MB, то увидеть, где она выделяется, и т.д.

    См WWDC видео, такие как в 2013 году Fixing Memory Issues или в 2012 году iOS App Performance: Memory (и игнорировать тот факт, что iOS находится в названии, так как многие из этих принципов одинаково хорошо применяются в MacOS), что иллюстрирует, как диагностировать такие проблемы.

+0

Я немного сузил проблему. Если я пытаюсь отправить несколько запросов одновременно, он быстро вынимает память. Например, я бы послал 50 запросов одновременно, дождитесь завершения всех 50, затем отправьте следующую партию. Это вызвало большой объем использования памяти, который никогда не будет освобожден. Но отправка только ОДНОГО запроса за раз, 5000 в строке, не использует много памяти. Проблема в том, что для завершения требуется намного больше времени. Любая идея, почему одновременные запросы питаются памятью? Я обнаружил, что создание одного сеанса (не используя sharedSession) и повторное использование дает наилучшие результаты, как вы предлагали. – hundley

+0

При запуске параллельных запросов (и я бы не делал больше 4 или 5 за раз, во всяком случае), использование пиковой памяти должно увеличиваться, но оно должно быть освобождено, когда эти запросы будут выполнены. Когда вы посмотрели на распределения, которые не были освобождены, что вы нашли? – Rob

+0

Я думаю, мне нужно сделать еще несколько исследований по использованию инструментов, потому что я не совсем уверен, как интерпретировать то, что я вижу в Allocations. Я бы, конечно, ожидал, что использование памяти будет увеличиваться, когда будут сделаны запросы, но странно, что они не освобождаются по завершении. – hundley

Смежные вопросы