#java #многопоточность #memory
Господа, насколько я понимаю модель памяти JVM выглядит так: если поток вызывает некий метод класса, то все локальные переменные которые там используются будут созданы не в HeapMemory, а в StackMemory. Этот StackMemory тоже очищается GC и тоже входит как слагаемое в полную доступную JVM память (ее можно получить как Runtime.maxMemory()), и, следовательно, чем больше потоков - тем больше занято памяти, даже при том что HeapMemory остается без изменений. Т.о. можно записать: Runtime.freeMemory() = Runtime.maxMemory() - Thread1Stack - Thread2Stack - ... - HeapSpace. Поправьте меня, пожалуйста, если я не прав. К чему я это спрашиваю: в моем приложении есть специальный поток-наблюдатель, который все время логгирует значение Runtime.freeMemory() и иногда оно опускается до сотен байт (однажды вообще было Runtime.freeMemory() = 8 ). Это приводит к тому, что процесс замедляется и Томкат не отвечает на HTTP запросы. Возникает вопрос: может ли при таком низком значении памяти запускаться GC? Я предполагаю, что должна быть связь оптимального количества потоков не только с количеством процессоров, но и с размером памяти. Как мне определить эту связь? У меня Томкату доступно Runtime.maxMemory() = 64МБ, при этом обычно мое приложение запускает 3-4 потока, максимум до 10-12. Мне казалось, что такая нагрузка подходит для процессора т.к. все эти мои потоки очень много спят. Однако судя по тому как мало памяти остается - думать надо не только о процессоре, но и о памяти. Итак, как понять какое количество потоков оптимально для многопоточного приложения? Какие кроме Runtime.freeMemory() методы отслеживания состояния памяти вы используете? (я не могу запустить профайлер на удаленном хостинге).
Ответы
Ответ 1
Вы не правы. Объекты всегда создаются в куче. В стеке живут примитивные типы (byte, char, short, int, long, boolean). В стеке хранятся ссылки на объекты в куче. Все ваши последующие рассуждения, как следствие, не верны. Если у вас всё встревает или даже падает по OOM, то у вас утечка. В общем, количетсво потоков и память связаны только когда потоков очень много (тысячи). Кроме того, каждому потоку можно указать конкретный размер стека, если вы знаете, какова максимальная требуемая глубина и нет рекурсии. Так что количетсво потоков выбирается таким образом, чтобы оно по возможности не было пропорционально количеству данных приложения и количеству пользователей. Что же до трёх потоков, то вы забываете о самом томкате, который запускает... очень немало потоков (в зависимости от конфигурации).Ответ 2
"Этот StackMemory тоже очищается GC" - неверно. Размер стека постоянен. Заполненая часть меняется, но не с помощью GC, а при процедурных переходах. Другое дело, что GC туда заглядывает, чтобы найти ссылки на живые объекты, которые не надо вычищать.
Комментариев нет:
Отправить комментарий