- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
Steps to reproduce:
var s = "a huge, huge, huge string...";
s = s.substring(0, 5);
Expected results: s takes five bytes of memory, plus some overhead.
Actual results: s takes a huge, huge, huge amount of memory.
Unfortunately, most String functions use substring() or no-ops internally: concatenating with empty string, trim(), slice(), match(), search(), replace() with no match, split(), substr(), substring(), toString(), trim(), valueOf().
My workaround is:
function unleakString(s) { return (' ' + s).substr(1); }
But it's not satisfying, because it breaks an abstraction and forces me to think about memory allocation.
sqlhack 25.08.2021 23:34 # 0
3.14159265 26.08.2021 13:58 # +1
Какой time-paradox )))
sqlhack 25.08.2021 23:37 # 0
guest6 26.08.2021 14:02 # +1
1. Мне за эту питушню не заплатили ни евроцента.
2. Была и другая кодопитушня поинтереснее. Там надо было реализовать что-то новое, а не пердолиться с забытым кодом.
3. Оно и так работало. Только раз в пару лет при полном перекачивании надо было запустить 4-5 раз парсер ради 20-25к постов. Это 4-5 запусков команды вместо одного раз в пару лет. При регулярной докачке по 50-200 только изменившихся постов питушня не падает.
3.14159265 26.08.2021 14:06 # +2
И ноду предлагают пихать в СЕРВЕРА (!) и ни о чём ни думать.
И тут мы опять приходим к тому о чём я уже говорил:
Они не сделали язык с автоматическим управлением памятью.
Они просто сделали говно на котором писать нельзя.
И в этом и заключается фокус.
Нода нам даёт абстракции на которых мы уже и пытаемся что-то сваять.
Очевидно, что сваять ничего нельзя - поэтому отовсюду течёт память.
Как мы видим гц-мразь опять обосралась, но с неё так никто за это и не спросил.
guest6 26.08.2021 14:12 # 0
Вот. А я использовал серверную технологию для написания клиентского скрипта, поэтому и обосрался.
> сваять ничего нельзя - поэтому отовсюду течёт память
У меня есть сервер под Node, там крутится более нетривиальная питушня, чем парсинг базы, но даже после месяцев работы потребление остаётся в рамках 80-150МБ. Иногда смотришь: после инициализации становится 160МБ, а потом обновляешь статистику, а там ГЦ всё смыл.
3.14159265 26.08.2021 14:17 # 0
Оно тоже парсит строки?
Речь о конкретной ошибке:
https://www.just-bi.nl/a-tale-of-a-javascript-memory-leak/
> использовал серверную технологию для написания клиентского скрипта, поэтому и обосрался.
Это плохо говорит о такой серверной технологии.
А самое печально что даже нет нормального метода для явного копирования части буфера в новую строку.
> return (' ' + s).substr(1);
Это хак, и довольно неочевидный.
guest6 26.08.2021 14:39 # +1
Действительно. На C++ аналогичная программа бы заняла без GC 10 ГБ и упала бы только в 2025 году, когда постов было бы настолько много, что свободной памяти и места на диске бы не хватило.
Кстати, сейчас и 20К постов вывозит. Или 64битная версия работает с 2ГБ, или сборщик мусора стал агрессивнее.
Интересно было наблюдать за работой в content mode. Если версии с регулярками за минуту жрали память линейно, то в версии с парсером HTML за свои минуты работы GC натужно чистил память вилкой и не давал ей линейно расти. Но всё равно мой код его подебил. Причём во второй половине времени бОльшая часть ресурсов, похоже, тратилась на работу GC, чтобы урвать хоть какой-то кусок памяти.
3.14159265 26.08.2021 15:22 # +1
guest6 26.08.2021 15:27 # 0
Desktop 27.08.2021 11:48 # 0
guest6 27.08.2021 11:49 # 0
guest6 26.08.2021 14:39 # 0
3.14159265 26.08.2021 14:40 # 0
guest6 26.08.2021 15:02 # +1
Если бы погуглил её лет пять назад, вообще бы никаких проблем не было.
list mode: 3.2GB (во время парсинга было 3GB, потом парсинг закончился, GC убрал до 2.6GB и докачались 24 обнаруженных повреждённых файла, после сохранения JSON стало 3.2)
content mode: 5.7GB (после 4ГБ стал активнее чистить и понизил коэффициент прямой потребления, но стал безбожно тормозить, по завершении парсинга занял 5ГБ, после сохранения JSON было 5.7ГБ)
stok mode: 2.4GB
html mode: 3.7GB
Есть мысль, что content mode может заработать и на 3ГБ (с 2ГБ сломался на 22757 из 27645, а с 8ГБ просто не так агрессивно водил вилкой).
Вообще, главная проблема тут в том, что я гружу в память всю базу. Если бы это был хотя бы MySQL-сервер, Node.js бы отправила ему в запросе новую питушню и освободила целиком, отправила и освободила, и так для каждого поста на ГК.
Так что тут не надо пердолиться, если архитектура кривая.
guest6 26.08.2021 15:06 # 0
guest6 26.08.2021 15:12 # 0
guest6 26.08.2021 15:18 # 0
3.14159265 26.08.2021 15:19 # +1
По идее ему нужна память для обработки одной самой большой страницы (хохлосрача) + немного для статы по юзерам.
> Питушня сожрала 4.6ГБ
O(N) по памяти.
guest6 26.08.2021 15:28 # 0
И для хранения всей базы ещё. Она же в памяти у меня, какой багор.
3.14159265 26.08.2021 15:30 # 0
Мы уже поняли что вся база СТОЛЬКО не занимает.
guest6 26.08.2021 15:30 # 0
удачи
guest6 26.08.2021 15:31 # 0
А так я сегодня больше времени потратил на поиск и проверку, чем все эти годы - на запуск проги.
3.14159265 26.08.2021 15:39 # +1
Реально работа с gc языком включает в себя снятие дампов, изучение таких флагов, тюнинг gc.
guest6 26.08.2021 15:45 # +3
Программист: Реально работа с gc языком включает в себя снятие дампов, изучение таких флагов, тюнинг gc.
CHayT 26.08.2021 15:55 # +1
guest6 26.08.2021 15:59 # +3
CHayT 26.08.2021 16:14 # 0
guest6 26.08.2021 15:44 # +1
Подмодули парсеров разных режимов в качестве интерфейса получают функции добавления поста, комментария и пользователя. Соответственно, если в них провести очистку строки от греха, эффект сработает сразу для всех парсером.
Добавил такое:
и обернул в это пришедшую от парсеров питушню
После этого в режиме pitux=4096 график mode content стал пилообразным. Намечался линейный рост но раз секунд в 10 ГЦ сбрасывал по 200-300МБ.
Парсинг закончился на 1.5ГБ, сохранение - на 2.1ГБ.
В режиме pitux=1024 (ко-кок, даже меньше, чем было с дефолтом) поцребление было с микропилами (ГЦ срезал десятками мегабайт), линейного роста не было. Что интересно, после опреелённого момента приложение тормозит секунд 5 и тактика ГЦ меняется. Для 4096 это были просто тормоза и линейный рост продолжался, а для 1024 стало линейное убывание. Парсинг закончился на 880МБ, сохранение - на 1.6ГБ.
Мда, мы с Вами были правы про
> кусков строк, от которых используется только небольшой слайс
guest6 26.08.2021 16:17 # +1
Парсер стока, судя по размеру, реально тянул за собой все считанные из файлов данные.
3.14159265 26.08.2021 19:36 # +3
Вот было бы у вас например 512 Мб памяти, тогда программа сразу бы получилась гораздо оптимальнее.
Чем больше современному программисту доступно памяти, тем большее говнище он пишет.
bormand 26.08.2021 19:43 # +3
guest6 26.08.2021 19:54 # +1
P.S. Уверен, что скрипт бы и без очистки строк работал и так месяцами, поскольку при обновлении поста GC бы удалял старую психозу :) Правда, на 4-8ГБ
bormand 26.08.2021 20:05 # +2
guest6 26.08.2021 19:52 # +2
Не было бы JS и куч памяти - не было бы всей питушни, что я писал. На сишке под микроконтроллер я бы не брался писать парсер ГК.
guest6 26.08.2021 19:53 # +2
Выскоуровневые ЯПы быстро развращают просто. Если бы ты никогда в жизни не ел ничего слаще `Borland C 3.1` под DOS, то как миленький бы писал на нём что угодно.
Писали же чуваки всякие тосеры, редакторы для фидонета, целые файловые менеджеры...
guest6 26.08.2021 19:59 # 0
bormand 26.08.2021 20:01 # 0
Ой не факт... Сейчас везде тенденция сводить полезную функциональность к минимуму.
Desktop 26.08.2021 20:30 # 0
Desktop 26.08.2021 21:17 # 0
Steve_Brown 27.08.2021 11:46 # 0
или c собственным gc:
можно даже фоновым:
Steve_Brown 27.08.2021 11:49 # 0
3.14159265 27.08.2021 12:21 # +2
Сравнение немного некорректно.
Во-первых, js не предоставляет программисту альтернативной реализации строк.
Во-вторых, они даже не удосужились добавить метод подобный «squeeze».
Программист вынужден использовать неочевидные, недокументированные хаки, основанные на предположениях как оно работает внутри.
Проблема эта существует много лет. Но решать её не торопятся. Вместо этого в новые стандарты напихивают разные class, constructor, extends, super,
И самое главное: В-третьих, достойная реализация гц в случае критической нехватки памяти могла бы анализировать ссылки подстрок (которые полностью спрятаны под капотом) и копировать использующиеся фрагменты в меньшие подстроки.
Ничего этого в js нет.
guest6 27.08.2021 12:24 # +1
Это было бы самое лучшее решение. И не было бы тормозов из-за лишних маллоков как в разных крестах, и память бы не просиралась.
Оптимизация с хранением слайсов, в общем-то, полезная, пока памяти на неё хватает.
3.14159265 26.08.2021 14:03 # +2
1024-- рассказал что в node утекает память.
https://govnokod.ru/27615#comment664411
> Мой парсер постов ГК (работает с HTML-файлами постов на диске, которые скачал загрузчик) раньше мог распарсить не более 5К постов, от большего количества он тупо набирал 1.5ГБ и дох.
> Сборщику мусора просто не давали нормально отработать, какие тут тормоза!
> Вероятно, память жрётся из-за ошмётков объектов парсинга и кусков строк, от которых используется только небольшой слайс.
guest6 26.08.2021 16:35 # 0
ABryCTOBCKuu_nemyx 26.08.2021 14:31 # +4
j123123 26.08.2021 15:06 # +4
defecatinho 26.08.2021 16:56 # 0