LINUX.ORG.RU

ЖАБА съела мою память!

 , , , ,


0

0

Здравствуйте, объясните мне, почему любое приложение на этом языке протекает? Вот запускаешь ты его, сразу 400 уходит, хотя там 100 за глаза, ну ладно. Через пару часов это уже 4000 (при этом всё работает нормально). Но далее закономерно начитаются проблемы, даже если памяти избыток.

В частности, это касается игрушек, Runescape там, Wakfu и остальное. В определённый момент, всё начинает сильно, всё сильнее и сильнее, подвисать, тормозить и зависать. Причём, никакие игры с ключами, ограничениями памяти, переключениями режимов GC и прочим таким, ни к чему не приводят — становится только хуже. Например, можно начинать с самого начала: сделать чтобы GC приходил почаще и вёл себя агрессивней. Подфриживания будут чаще и с самого начала, но при этом памяти хватит на дольше (вроде бы). Это продолжается уже много-много лет. Неужели это происходит только у меня и никто этого не видит?

И попутно, у оракловской сборочки есть панель управления приложениями с профайлером и прочими ништяками, можно ли иметь что-нибудь похожее для openjdk? Мне она не нужна, просто интересно.



Последнее исправление: linuxnewbie (всего исправлений: 2)
Ответ на: комментарий от crutch_master

Нет же. Жабу делали, чтобы еще лучше абстрагироваться от железа. Знаковые целые по дефолту, одинаковые размеры флоатов везде и т.д. Потом всё пошло не туда и сейчас мы имеем десткопный жабасофт x86 и amd64.

Секунду-секунду. Да, ты прав в том, что жаба условно независима от железа и с этой целью разрабатывалась. Но зачем сборщик мусора аля Smalltalk/Modula-3? (оба мертвы) Он ведь не имеет никакого отношения к железонезависимости - делай ручное выделение/высвобождение, подсчет ссылок, в конце-концов - кресты в то время уже прекрасно существовали наравне с адой (в последней был опциональный сбор мусора, реально не имевший реализации). Абстрагированное от реализации выделение-высвобождение, да, но достаточно низкоуровневое, как того требуют постулируемые Sun-ом цели. Ведь именно из-за сбора мусора Java провалились как платформа для браузеров, ибо тормоза и жор памяти, которые не удается устранить до сих пор.

Что дает сбор мусора? Ниже требования к писаке, ниже ответственность - все эти задачи перекладываются на рантайм, который сидит, анализирует структуру программы, и думает «нужно ли здесь добавить высвобождение памяти или нет?». Ведь не один же человек принимал решение, мол «хочу чёта со сбором мусора сделать, устал уже я от этих ручных высвобождений». Нет, менеджмент изначально делал ставку на макак, которые будут сокращать затраты на разработку. Эта картина сохранилась до сих пор.

byko3y ★★★★
()

Не могу привести ссылку, но в одном блоге разработчика на java читал, что они столкнулись с проблемой утечки памяти у JVM. После долгих разборок выяснилось - было виновато ядро линукс, на виндовс такая проблема отсутствовала.

Miha
()
Ответ на: комментарий от byko3y

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

Хаскель тоже на макак расчитывался?

Miha
()
Ответ на: комментарий от Miha

Ну нет, у меня течёт одинаково чудовищно, в том и дело. А вообще мне нравятся прохладные истории, где винят ядро, приведите, если найдёте.

linuxnewbie
() автор топика
Ответ на: комментарий от linuxnewbie

Ну смотри. Я тебе как жава разработчик попробую обрисовать ситуацию. Может чего полезного извлечёшь.

Твой главный инструмент по ограничению жора жавы это ключ -Xmx. Это размер кучи, по сути там все жава объекты и лежат. Если ты его задашь слишком маленьким, жава начнёт падать с исключением OutOfMemoryException. Если ты его задашь впритык, падать она не будет, но будет очень много времени тратить на сбор мусора. Если у тебя программа всегда потребляет примерно одинаковый объём памяти, то надо ставить примерно полуторный объём этой памяти, можно уменьшить до 1.2, меньше уже не стоит. Если у тебя есть пиковое потребление памяти, то, понятное дело, надо ставить не меньше этого пика, иначе свалится. Сколько поставишь, столько сожрёт и назад не отдаст, даже если уже не надо, это минус JVM. Если ты его не задашь, он выставится автоматически, в зависимости от объёма памяти на твоём компьютере. Например в 1/4 от общего объёма. Поэтому задавать надо всегда, т.к. тебе видней, сколько надо выделить программе, JVM точно фигню выставит.

Кроме этого жрать память могут нативные библиотеки. Тут ты ничего не сделаешь. Ну только лезть в код, вкуривать, в общем вряд ли.

Кроме этого жрать память может так называемая offheap память. Это когда некоторые разработчики считают себя умней JVM и жрут память вне хипа, самостоятельно управляя ею. Тут тоже ты ничего не сделаешь, ну можно покурить исходники, возможно там разработчики предусмотрели какие-то свои лимиты. В целом это дурной тон и используется редко.

Понятно, что во всех случаях программа может течь. Это баг, который надо исправлять. Если есть желание - запусти с -Xmx поболььше, подожди, чтобы она хорошо так потекла, и сделай дамп. Потом этот дамп отправляй разработчику и проси пофиксить. Чтобы быть уверенным в утечке, лучше подцепиться JConsole к программе и помониторить график хипа, пожмякать кнопочку «GC». Используемая память это именно тот объём, который появляется после GC. Если видно, что с течением времени он ощутимо растёт, а причин этому не заметно, можно этим заняться. Имей в виду, что дамп содержит все данные программы, среди которых могут быть твои приватные данные, пароли, которые ты вводил в эту жава-программу и всё такое прочее.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 2)
Ответ на: комментарий от Legioner

Хорошо, скажите тогда как жаборазработчик, почему только жабоприложения текут? Исключительная привилегия жабы — течь? И иногда жабоскриптоприложения, но те обычно проходят какой никакой QA и не вытекают на гигабайты гигабайт в час и если судить по электрону, так вообще не текут. И ведь эти приложения запускают как минимум десятки, сотни тысяч людей, и никто ничего не видит?

linuxnewbie
() автор топика
Ответ на: комментарий от linuxnewbie

Вопрос некорректный. Текут все приложения. Ничего такого, из-за чего жава могла бы течь больше остальных, в ней нет.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

Вопрос некорректный. Текут все приложения.

И ответ тоже некорректный:

C - valgrind, gdb

Java - ???

Будьте любезны поправить, если что не так.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

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

В джаве утечки памяти имеют другой характер например у тебя есть структура которая должна жить протяжении всей жизни программы к примеру хеш таблица которая для каждого подключенного юзера хранит вебсокет соединение. Если ты при отключении юзера руками из этой таблицы не удалишь соединение, то GC его удалить не сможет потому, что он думает что раз ссылка на эту структуру есть и путь из GC roots соответственно, значит ты сделал это осознанно и за чем-то она тебе нужна. Определить нужна или нет можно только зная бизнес логику приложения, способов автоматизировать поиск таких утечек я не знаю обычно программист делает heap dump и смотрит на что расходуется память через VisualVM/JConsole/Mission Control.

mythCreator
()

И попутно, у оракловской сборочки есть панель управления приложениями с профайлером и прочими ништяками, можно ли иметь что-нибудь похожее для openjdk? Мне она не нужна, просто интересно.

visualvm показывает состояние потоков, памяти, позволяет снять дам и sql подобным языком поискать объекты в нем.

Aber ★★★★★
()
Последнее исправление: Aber (всего исправлений: 1)
Ответ на: комментарий от mythCreator

способов автоматизировать поиск таких утечек я не знаю

Ты не одинок в этом.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от wgetcurl

Похоже на правду, примерно так я себе это и представляю.

linuxnewbie
() автор топика
Ответ на: комментарий от Aber

Да, спасибо. Мы тут немного выше по треду выяснили, что текут видимо нативные библиотеки. Без которых приложения на java показывают производительность на уровне cpython без нативных библиотек.

linuxnewbie
() автор топика
Ответ на: комментарий от Legioner

Сколько поставишь, столько сожрёт и назад не отдаст, даже если уже не надо, это минус JVM. Если ты его не задашь, он выставится автоматически, в зависимости от объёма памяти на твоём компьютере.

Вот. Вся описываемая тобой процедура «тонкой настройки» - это бесполезная хрень, которую выставлять неудобно и не всегда вообще возможно. Меня убивает, что за все эти годы никто так и не придумал единственной настройки - чистить память при низкой нагрузке и отдавать память ОС-и. И всё, оказывается не нужна вся эта возня с выбором размера кучи, который ты все равно никогда не угадаешь.

byko3y ★★★★
()
Ответ на: комментарий от Legioner

Вопрос некорректный. Текут все приложения. Ничего такого, из-за чего жава могла бы течь больше остальных, в ней нет.

Вопрос исключительно корректный. VSCode, Atom не текут и не жрут память, работают быстрее, чем любая жабоиде, при этом они сделаны на электроне, который хром+Javascript с динамической типизацией и хэш-таблицей в качестве основного типа данных.
Видит бог, я пытался защищать жабу в удаленном треде про node.js, но здесь я никак не могу согласиться, ведь одинаковая программа на JS и Java жрет столько же или больше памяти именно на последней, пусть и ненамного больше. Но ты понимаешь разницу между JS и Java? Ну ты представь, что я бы принес IDE на питоне, и оказалось, что по скорости работы оно сравнимо с жабоиде, а памяти питониде жрет столько же или меньше - ты бы снова говорил, что жаба не течет?

byko3y ★★★★
()
Ответ на: комментарий от mythCreator

Если ты при отключении юзера руками из этой таблицы не удалишь соединение, то GC его удалить не сможет потому, что он думает что раз ссылка на эту структуру есть и путь из GC roots соответственно, значит ты сделал это осознанно и за чем-то она тебе нужна.

Это ты сам придумал?

Это конкретно в каком фреймворке оно так работает?

Не пили свои непонеятные глючные штуки, а пользуйся EJB или хотябы Spring на худой конец.

От ты ляпнул так ляпнул.

И каким ты образом захотел сделать утечку памяти самописной какашкой?

HIS
()
Ответ на: комментарий от Deleted

valgrind в C решает проблемы, которых в принципе не может быть в Java. Для борьбы с утечками снимают хип дамп и исследуют его.

Legioner ★★★★★
()
Ответ на: комментарий от byko3y

Вот. Вся описываемая тобой процедура «тонкой настройки» - это бесполезная хрень, которую выставлять неудобно и не всегда вообще возможно.

Это не тонкая настройка, это базовая настройка и это очень полезная хрень. С тонкими настройками всё куда сложней.

Меня убивает, что за все эти годы никто так и не придумал единственной настройки - чистить память при низкой нагрузке и отдавать память ОС-и.

Потому, что это никому не надо. Java это язык для серверного приложения, у которого есть определённый лимит (чаще всего это тупо вся памяти сервера, ну минус немного чтобы не свопило). Все проблемы от того, что люди пытаются применять JVM для тех областей, для которых она не предназначена.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

из-за чего жава могла бы течь больше остальных, в ней нет.

которых в принципе не может быть в Java

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

Deleted
()
Ответ на: комментарий от byko3y

Вопрос исключительно корректный. VSCode, Atom не текут и не жрут память, работают быстрее, чем любая жабоиде

Idea не течёт и работает быстрей VSCode и Atom вместе взятых. Как тебе такое, Элон Маск?

одинаковая программа на JS и Java жрет столько же или больше памяти именно на последней, пусть и ненамного больше

Есть пруф? Ну-ка приведи эту одинаковую программу. Уверен, нифига не одинаковая. Аккуратно написанную программу на Java порвёт только C.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

Твой главный инструмент по ограничению жора жавы это ключ -Xmx

Есть ещё такая штука как управление выделением памяти в Linux. В виндовс оно работает полуавтоматически. В Linux нужно задавать размер максимальной области памяти для процесса в ручную.

Я сам с этим столкнулся лет 5 назад когда начал разрабатывать очень ресурсоёмкий проект и мне нужно было более 8 гигабайт на JVM.

HIS
()
Ответ на: комментарий от Deleted

Где я лукавлю? Ты valgrind использовал? Он отлавливает некорректные чтения памяти (невозможно в Java), двойные free (невозможно в Java), неосвобождение памяти после malloc (невозможно в модели с GC). Как ты себе представляешь автоматический поиск утечек в языке с GC? Любая утечка это проблема логики, а такие проблемы может найти и исправить только программист, а не инструмент.

Legioner ★★★★★
()
Ответ на: комментарий от HIS

Блин, да элементарные кривые хэши же ж. Ссылка из корня есть, а удалить обычными способами низя. ThreadLocal - это вообще катастрофа.

Не пили свои непонеятные глючные штуки, а пользуйся EJB или хотябы Spring на худой конец.

Я довел этот совет до идеала - я не пижу на жаве.

byko3y ★★★★
()
Ответ на: комментарий от Legioner

такие проблемы может найти и исправить только программист, а не инструмент.

Что ж это за «логика» такая, что под неё даже «инструмент» сделать «невозможно»? Не лукавство?

Deleted
()
Ответ на: комментарий от byko3y

Я довел этот совет до идеала - я не пижу на жаве.

Так и не пижи тут.

HIS
()
Ответ на: комментарий от mythCreator

например у тебя есть структура которая должна жить протяжении всей жизни программы к примеру хеш таблица которая для каждого подключенного юзера хранит вебсокет соединение. Если ты при отключении юзера руками из этой таблицы не удалишь соединение, то GC его удалить не сможет потому, что он думает что раз ссылка на эту структуру есть и путь из GC roots соответственно, значит ты сделал это осознанно и за чем-то она тебе нужна

Твоя проблема решается через WeakHashMap, если что, это к слову. Вручную не надо ничего удалять.

Legioner ★★★★★
()
Ответ на: комментарий от Deleted

Нет, не лукавство.

Впрочем 99% C-шных программ и библиотек не чистят всю память после выхода. В том же valgrind-е уйма фильтров для подавления сообщений об утечках из системных библиотек. Поэтому тут Java не особо проигрывает.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)
Ответ на: комментарий от Legioner

Поэтому тут Java не особо проигрывает.

Проигрывает, отсутствием инструментария.

Deleted
()
Ответ на: комментарий от Legioner

Мне всё-таки кажется между утечкой 1 раз на весь цикл жизни приложения и регулярными утечками в процессе работы есть разница. Ближайшее что я могу представить, это как ИКУ текла в потрошках, по версии valgrind, она определённо не должна была. Любые серьёзные библиотеки не должны течь. Впрочем, программа действительно может не освобождать память, если ядро в любом случае её почистит при закрытии. Под утечками обычно подразумевают факт того, что со течением временем работы, программа начинает требовать себе всё больше и больше памяти, намного больше необходимого и зачастую просто так.

linuxnewbie
() автор топика
Ответ на: комментарий от Legioner

Это не тонкая настройка, это базовая настройка и это очень полезная хрень. С тонкими настройками всё куда сложней.

Да, это не тонкая настройка - это толстый костыль, которым подпирают неспособность JVM самостоятельно управлять размером своей кучи.

Потому, что это никому не надо. Java это язык для серверного приложения, у которого есть определённый лимит (чаще всего это тупо вся памяти сервера, ну минус немного чтобы не свопило). Все проблемы от того, что люди пытаются применять JVM для тех областей, для которых она не предназначена.

Вот выше же писали про ключевую фичу жавы, то есть кроссплатформу - это ведь не категория серверов, это категория конечных устройств юзеров, которые нецентрализованы и их бывает много разных.
Я возражал, мол, для бизнес-логики жава подходит даже лучше, чем для конечных пользовательских устройств. Просто оказалось, что жава не умеет толком ни в однопоточный пользовательский интерфейс, ни в многопоточный, и в итоге она сама себя загнала в эти рамки.
Но все еще хуже: даже на серверах бизнес-логики нельзя как попало применять JVM - вы можете применять ее только для задач, требующих фиксированное выделение памяти. Типа «вы можете купить автомобиль любого цвета, если этот цвет - черный».

byko3y ★★★★
()
Ответ на: комментарий от Miha

Хаскель тоже на макак расчитывался?

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

byko3y ★★★★
()
Ответ на: комментарий от Legioner

Idea не течёт и работает быстрей VSCode и Atom вместе взятых. Как тебе такое, Элон Маск?

Спасибо, я запускал пару дней назад. При открытии большого проекта поделие джетмозгов минут 5-10 тормозило и ограничивало функции, потом после каждого чистого запуска IDE сжирало 500 Мб на ровном месте. Atom работает сразу и жрет 350 Мб.
Я тоже не верил в чудо Electron-а, но оно вполне реально, и этот фреймворк не просто так сейчас много где применяют.

Есть пруф? Ну-ка приведи эту одинаковую программу. Уверен, нифига не одинаковая.
Аккуратно написанную программу на Java порвёт только C.

Вот текста тестовых прог: https://pastebin.com/xKn0z2Q1
По нашим тестам выделение плюс-минус похожее было, но я напоминаю, что это JS против жавы.

byko3y ★★★★
()
Ответ на: комментарий от Deleted

Что ж это за «логика» такая, что под неё даже «инструмент» сделать «невозможно»? Не лукавство?

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

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Я тоже не верил в чудо Electron-а, но оно вполне реально

vscode + Language Support for Java ? Тормозилово, поставил его днями на свой старый ноут с core2dou и это жесть... эклипс 2019.03 лучше работает.

Aber ★★★★★
()
Ответ на: комментарий от HIS

Вы точно поняли, что я про вебсокеты, а не делаю свой http сервер?

Это конкретно в каком фреймворке оно так работает?

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springfr... наследуешься в спринге от этого класса реализуешь бизнеслогику работы с вебсокетами которая нужна

пользуйся EJB

нет спасибо

mythCreator
()
Ответ на: комментарий от Legioner

Да, все верно если хранить WebSocketSession то так и есть, потому что у tomcat внутри есть на него ссылки, но там был декоратор, на который ссылки только в мапе.

mythCreator
()
Ответ на: комментарий от linuxnewbie

Мне всё-таки кажется между утечкой 1 раз на весь цикл жизни приложения и регулярными утечками в процессе работы есть разница.

С точки зрения valgrind нет. И то и то это неосвобождённая память после malloc. С точки зрения программиста, конечно, есть. Примерно это и есть то, что называется утечкой в Java.

Впрочем, программа действительно может не освобождать память, если ядро в любом случае её почистит при закрытии.

И это с какой-то точки зрения даже правильно, т.к. освобождение памяти перед завершением работы это просто ненужные циклы процессора. Но с точки зрения valgrind это утечка и если ты так делаешь (как и остальные 99% программистов), то пользоваться valgrind-ом для поиска утечек будет куда сложней, чем если у тебя всегда чистый запуск, а любая ошибка - повод для исправления бага.

Под утечками обычно подразумевают факт того, что со течением временем работы, программа начинает требовать себе всё больше и больше памяти, намного больше необходимого и зачастую просто так.

Да, но тут вопрос же в том, что якобы valgrind даёт возможность сишникам не беспокоиться об утечках, ибо их поиск становится тривиален, а жаверы лишены такого счастья и им приходится вручную копаться в дампах.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)
Ответ на: комментарий от byko3y

Вот выше же писали про ключевую фичу жавы, то есть кроссплатформу - это ведь не категория серверов, это категория конечных устройств юзеров, которые нецентрализованы и их бывает много разных.

Жава уже давным давно не кросс-платформенна. Её не запустишь в браузере. Её не запустишь на айфоне. Её даже на андроиде запустить непросто. Все библиотеки для GUI безнадёжно устарели. Windows WPF уже сколько лет, что у жавы есть? Ничего? Вот RHEL 8 зарелизился с Wayland. Поддерживает Swing его? Через легаси X? Вот как-то так. Задумки у них 20 лет назад были широкие, сейчас по факту жава это серверный бэкэнд.

Legioner ★★★★★
()
Ответ на: комментарий от byko3y

Спасибо, я запускал пару дней назад. При открытии большого проекта поделие джетмозгов минут 5-10 тормозило и ограничивало функции, потом после каждого чистого запуска IDE сжирало 500 Мб на ровном месте. Atom работает сразу и жрет 350 Мб.

Потому, что у поделия функционала в тысячу раз больше, чем у текстового редактора?

Вот текста тестовых прог: https://pastebin.com/xKn0z2Q1

Так ты в JS кладёшь в массив, а в Java кладёшь в хешмап. Или клади в JS в хешмап или в Java клади в массив.

Legioner ★★★★★
()
Ответ на: комментарий от mythCreator

пользуйся EJB

нет спасибо

Очень зря. Весьма продвинутая и оптимизированная штука.

То что ты ленишься изучить годные вещи - это тебе минус.

я про вебсокеты

Они как-то раздельно от нормального веб программирования?

HIS
()
Ответ на: комментарий от mythCreator

Вы точно поняли, что я про вебсокеты, а не делаю свой http сервер?

Ты пишешь некую хренотень, буто пишешь свой http сервер.

HIS
()
Ответ на: комментарий от Legioner

valgrind даёт возможность сишникам не беспокоиться об утечках, ибо их поиск становится тривиален, а жаверы лишены такого счастья и им приходится вручную копаться в дампах.

Точно. Лучше не скажешь.

Deleted
()
Ответ на: комментарий от Deleted

А я о том, что ТС уже некоторые вариантов инструментов для поиска утечек подсказали, тот же VisualVM, а есть еще Eclipse Memory Analyzer, NetBeans Profiler, JProfiler, JRockit, Patty in action, GCeasy. Но проблема не в том, что нечем искать утечку - проблема в том, что некому искать утечку и исправлять ее. И также проблема в том, что чертова JVM не отдает память.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

проблема в том, что чертова JVM не отдает память.

И снова, лучше не скажешь.

Deleted
()
Ответ на: комментарий от byko3y

что чертова JVM не отдает память.

Отдаёт если не быть идиотом в программинге. Есть пару правил как попросить систему отдать память. Но все же лентяи и перебрасывают свои проблемы на других. Просить у нынешних мега молодых программеров не принято. Им всё должно подносится на блюдечке и упрашивать - «ну сделай отпуск объекта и пропиши null для того что ты не юзаешь». Это вам тепилоидам нужно? Вам нужна Сири котрая будет вас упрашивать и делать миньет?

HIS
()
Ответ на: комментарий от HIS

То что ты ленишься изучить годные вещи - это тебе минус.

Есть очень много годных вещей и жизни не хватит, чтобы все изучить. Пока что я не вижу смысла переходить со spring на java EE.

Они как-то раздельно от нормального веб программирования?

Вы пока не объяснили что не нормального я делаю, но на всякий случай уточню, что всю низкоуровневую работу делают spring и tomcat. Я реализую только бизнес логику приложения имплементировав WebSocketHandler. Если более конкретно, то в методе afterConnectionEstablished я должен где-то сохранить WebSocketSession чтобы при наступлении нужного события иметь возможность дернуть у него метод sendMessage и послать определенным группам людей сообщение.

mythCreator
()
Ответ на: комментарий от mythCreator

Я работаю больше 15 лет в веб технологиях. Использую Энтерпрайз технологии. Проблем нет.

Советую и тебе.

HIS
()
Ответ на: комментарий от mythCreator

Да. Тут вопрос именно в том. Ты типа залётная птица или таки ты прогер.

Сейчас технологии настолько сложны, что нельзя за неделю вникнуть хоть во что нибудь. Нужно тратить годы.

А так, если ты прыгаешь туда-сюда - ты просто ни на что не годное говно в итоге.

HIS
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.