|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
Всем привет, столкнулся с проблемой, когда потребление памяти имеет ненормальный характер. Суть работы приложения-обращение к стороннему API, получения от него JSON и его парсинг. В упрошенной схеме это выглядит так Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25.
Json-документы тяжелые- могут быть и по 4 Мб. Проблема: постепенное увеличение потребления оперативной памяти и периодическим скачкобразными "взрывами". GC не уменьшает значительно потребление памяти, пару десятков мегабайт освободит и все. На графике видно, что сначала происходит линейный рост потребления памяти с небольшим увеличением в динамике, потом когда потребление памяти становится 150 мб происходит резкий скачек до 308 мб. Причем и при 150мб и при 308 обрабатывается документ одного и того же размера (json около 2мб). Я произвел профилирование потребление памяти, которое показало, что наибольшим потребителем является "TlsOverPerCoreLockedStacksArrayPool+LockedStack<Byte>" и "JsonDocument". Мне не понятно, почему память течет, ведь все закрыто using и она должна освобождаться или по крайней мере расти не такими семимильными темпами. Спасибо ... |
|||
:
Нравится:
Не нравится:
|
|||
24.02.2021, 17:35 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
... |
|||
:
Нравится:
Не нравится:
|
|||
24.02.2021, 17:36 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
... |
|||
:
Нравится:
Не нравится:
|
|||
24.02.2021, 17:36 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
У тебя из-за "yield" итерация отложенная. Вся хурда что только можно висит в памяти пока последовательность не будет перебрана целиком - возможно дело в этом. ... |
|||
:
Нравится:
Не нравится:
|
|||
24.02.2021, 17:42 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
vb_sub Код: c# 1.
Не надо парсить в JsonDocument, а сразу через JsonReader. В XML-е это называется SAX парсинг. Не нужен вам объект документа, лишний он тут и память жрёт. Постарайтесь обойтись без yield, можете переиспользовать коллекции или буферы. ... |
|||
:
Нравится:
Не нравится:
|
|||
24.02.2021, 18:51 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
hVostt vb_sub Код: c# 1.
Не надо парсить в JsonDocument, а сразу через JsonReader. В XML-е это называется SAX парсинг. Не нужен вам объект документа, лишний он тут и память жрёт. Постарайтесь обойтись без yield, можете переиспользовать коллекции или буферы. Ближайший родственник JsonReader из System.Text.Json это Utf8JsonReader, но он не поддерживает использование в асинхронных методах, то есть от самой точки входа в метод придется все делать синхронно. Это было бы терпимо, но оказывается HttpClient не имеет синхронных методов и нужно костылить ожидание асинхронной операции в синхронном коде. ... |
|||
:
Нравится:
Не нравится:
|
|||
25.02.2021, 09:08 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
vb_sub Ближайший родственник JsonReader из System.Text.Json это Utf8JsonReader, но он не поддерживает использование в асинхронных методах, то есть от самой точки входа в метод придется все делать синхронно. Это было бы терпимо, но оказывается HttpClient не имеет синхронных методов и нужно костылить ожидание асинхронной операции в синхронном коде. Ну у вас не десятки и не сотни мб объём JSON, не нужна вам асинхронность в парсинге. Просто исключите лишнее давление на память и GC. ... |
|||
:
Нравится:
Не нравится:
|
|||
25.02.2021, 11:35 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
После последовательного исключения кода, который мог бы повлиять на рост потребления оперативной памяти, я остановился на том что память уходит из-за метода отправки http-запроса. В частности я сделал тестовый метод, чтобы проверить мои подозрения. Я попробовал осуществить приведенные здесь советы- заменить yield, заменил JsonDocument на Utf8JsonReader, пробовал делать все синхронным- ничего не помогло. 22286181 объем суммарно может доходить и до 100 мб(множество запросов, где в каждом ответе приходит около 4 мб) Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
График потребления противоречивый- потребление памяти сначала росло где-то до 140, стабилизируется и остается на одном уровне, потом где-то на 300 запросе происходит вызов сборщика мусора, который очищает 2-е поколение и после этого скачкообразный рост потребления до 300 мб. ... |
|||
:
Нравится:
Не нравится:
|
|||
26.02.2021, 16:08 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
hVostt Ну у вас не десятки и не сотни мб объём JSON, не нужна вам асинхронность в парсинге. В парсинге там асинхронности скорее всего и нет - асинхронность в чтении стрима, который парсят. ТС, ты не пробовал готовые JSON-расширения для HTTP? (System.Net.Http.Json) ... |
|||
:
Нравится:
Не нравится:
|
|||
26.02.2021, 18:31 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
если у тебя блок памяти в 4мб и постоянно ...gc все что выше 85000 байт кидаешь в loh и утилизацию не будет вызывать пока gen0 может выделить память. ... |
|||
:
Нравится:
Не нравится:
|
|||
26.02.2021, 22:53 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
hVostt, как так-то? Ты же писал что там с помощью структур и GetHashCode все оптимизировано по самое нехочу ... |
|||
:
Нравится:
Не нравится:
|
|||
26.02.2021, 23:06 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
handmadeFromRu, Пробовал получать небольшие JSON-документы, чтобы ни гарантированно в LOH не попали- все равно ситуация идентичная. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.02.2021, 12:23 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
fkthat hVostt Ну у вас не десятки и не сотни мб объём JSON, не нужна вам асинхронность в парсинге. В парсинге там асинхронности скорее всего и нет - асинхронность в чтении стрима, который парсят. ТС, ты не пробовал готовые JSON-расширения для HTTP? (System.Net.Http.Json) В листинге Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9.
не доходит до этапа парсинга, а память уже течет. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.02.2021, 12:25 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
Попробовал сделать в консольном приложении все нормально. Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24.
... |
|||
:
Нравится:
Не нравится:
|
|||
27.02.2021, 12:44 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
vb_sub Попробовал сделать в консольном приложении все нормально. Становится все загадочней. Сделай в своем webapi какой-нибудь action в котором вообще ничего, а только код из этого консольного приложения. Только, понятно, ServiceCollection и проч. руками не создавай - просто заинжекть HttpClientFactory через ctor контроллера. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.02.2021, 14:45 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
fkthat hVostt, как так-то? Ты же писал что там с помощью структур и GetHashCode все оптимизировано по самое нехочу Ну ты сравнение-то посмотри с другими парсерами. По самое нехочу да. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.02.2021, 22:54 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
vb_sub, Проведи нагрузочное тестирование, найти корни, которые не убиваются GC. ... |
|||
:
Нравится:
Не нравится:
|
|||
27.02.2021, 22:56 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
hVostt Ну ты сравнение-то посмотри с другими парсерами. По самое нехочу да. Да я прикалываюсь просто. Я знаю, что он шустрый. К тому же, как выясняется, вроде бы, дело совсем не в JSON. Сдается мне, автор тут что-то нам недопоказывает. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.02.2021, 00:56 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
Вот такой код: Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9.
Вот такая картинка: С виду все ровно - мусорщик регулярно вызывается, расход памяти не растет. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.02.2021, 01:01 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
fkthat С виду все ровно - мусорщик регулярно вызывается, расход памяти не растет. Ты хоть using добавил )) fkthat Сдается мне, автор тут что-то нам недопоказывает. Да фиг бы с ним, не понял проблемы. Ну используется память, как бы и что ) ... |
|||
:
Нравится:
Не нравится:
|
|||
28.02.2021, 01:23 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
hVostt Ты хоть using добавил )) Да он на самом деле ни на что не влияет. Даже в доках есть, что HttpClient вообще можно использовать как singleton без всякого Dispose. И даже не можно, а нужно (если не используется IHttpClientFactory). Using тут так, чисто по привычке. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.02.2021, 03:07 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
fkthat hVostt Ты хоть using добавил )) Да он на самом деле ни на что не влияет. Даже в доках есть, что HttpClient вообще можно использовать как singleton без всякого Dispose. И даже не можно, а нужно (если не используется IHttpClientFactory). Using тут так, чисто по привычке. Using здесь определенно не нужен пруф . Используя его Вы нивелируете те возможности IHttpClientFactory, борящиеся c проблемами, которые порождает создание каждый раз нового HttpClient(socket exhaustion, httpclientPooling, dns caching). 22287430 У Вас потребление устаканилось на уровне 261 МБ при 100_000 запросах, однако Вас не на настрожило то, что приложение стартует с потреблением 90 МБ осуществляет операции с http-запросами, полностью их выполняет, и потребление памяти после этого не падает, хотя все ресурсы, затраченные на эти операции должны быть вычищены сборщиком мусора. К сожалению на графике не видно есть ли резкий скачек потребления памяти, подозреваю что скорее всего да, хотя по логике процесса память должна расти линейно. Причем эмпирически я выяснил что появление этого скачка зависит от количества итераций- на примере "https://jsonplaceholder.typicode.com/" Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
конечное потребление памяти-114МБ -потребление растет линейно, скачков нет Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
Конечное потребление-264 МБ Количество итераций увеличилось на 25%, потребление памяти увеличилось на 130%. Я бы мог это объяснить, если бы был какой-либо объект, который аккумулирует результат каждой итерации и он провалился в LOH, однако здесь после выхода из каждой итерации цикла не должно ничего остаться. Это все результаты на чистом проекте, с одним контроллером и одним Action-остальные side-эффекты исключены. 22287429 =false; Весь код выставил, все договорил, ничего не скрываю. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.02.2021, 13:09 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
hVostt vb_sub, Проведи нагрузочное тестирование, найти корни, которые не убиваются GC. Штатного профилировщика памяти будет достаточно или нужны сторонние инструменты для поиска корней? ... |
|||
:
Нравится:
Не нравится:
|
|||
28.02.2021, 13:11 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
vb_sub Количество итераций увеличилось на 25%, потребление памяти увеличилось на 130%. У меня абсолютно одинаковая картинка для 100, 200, и 1000 итераций, причем как с using так и без него. Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9.
Первый сборщик вызван при запросе 100 итераций, три вторых - для 200, последующие для 1000. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.02.2021, 15:12 |
|
AspCore течет память при интенсивном парсинге Json-документов
|
|||
---|---|---|---|
#18+
fkthat, такой же скачек есть. Нашел решение форк можно закрыть. Код: c# 1. 2. 3. 4. 5. 6. 7. 8.
единственный минус- нельзя использовать для десериализации Utf8JsonReader. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.02.2021, 15:16 |
|
|
start [/forum/topic.php?fid=18&tid=1354568]: |
0ms |
get settings: |
9ms |
get forum list: |
11ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
31ms |
get topic data: |
11ms |
get forum data: |
3ms |
get page messages: |
61ms |
get tp. blocked users: |
2ms |
others: | 12ms |
total: | 146ms |
0 / 0 |