Мы недавно перемещали много приложений от выполнения под RedHat linux JDK1.6.0_03 к Солярису 10u8 JDK1.6.0_16 (намного более высокие машины спецификации), и мы заметили то, что, кажется, довольно насущная проблема: при определенных загрузках наши JVMs вовлекают себя в "Смертельную Спираль" и в конечном счете выходят из памяти. Вещи отметить:
SIGSEGV
ошибки Наиболее важный момент - это: поведение проявляется в тех приложениях, которые внезапно получают наводнение данных (обычно через TCP). Это - как будто VM решает продолжать добавлять больше данных (возможно прогрессирующий он до TG) вместо того, чтобы выполнить GC на "newspace", пока это не понимает, что должно сделать полный GC и затем, несмотря на практически все в VM быть мусором, это так или иначе решает не собрать его!
Это звучит сумасшедшим, но я просто не вижу то, что еще это. Как еще может Вы объяснять приложение, за которое одна минута запинается и падает с макс. "кучей" 1 ГБ, и следующее работает просто великолепно (никогда не идущий о 256M, когда приложение делает точно то же самое),
Таким образом, мои вопросы:
В Oracle
WITH
START_DATE AS
(
SELECT TO_CHAR(TO_DATE('JANUARY 5 2010','MONTH DD YYYY'),'J')
JULIAN FROM DUAL
),
END_DATE AS
(
SELECT TO_CHAR(TO_DATE('JANUARY 30 2010','MONTH DD YYYY'),'J')
JULIAN FROM DUAL
),
DAYS AS
(
SELECT END_DATE.JULIAN - START_DATE.JULIAN DIFF
FROM START_DATE, END_DATE
)
SELECT TO_CHAR(TO_DATE(N + START_DATE.JULIAN, 'J'), 'MONTH DD YYYY')
DESIRED_DATES
FROM
START_DATE,
(
SELECT LEVEL N
FROM DUAL, DAYS
CONNECT BY LEVEL < DAYS.DIFF
)
-121--4648280- я бы предположил, что нормализованный способ будет более быстрым как для операций INSERT, так и для операций SELECT, хотя бы потому, что именно для этого будет оптимизирована любая RDBMS. Часть «Объем задействованных данных» тоже может быть проблемой, но более разрешимой - как долго вам нужны эти данные сразу на руках, можете ли вы архивировать их через день, пару недель или 3 месяца и т.д.? SQL Server может справиться с большим количеством проблем.
Эти данные о событии будут постоянно передаваться в потоковом режиме, поэтому время вставки так же важно, как время запроса.
Вариант 3: Если у вас действительно есть много данных, постоянно передаваемых в потоковом режиме - создайте отдельную очередь в общей памяти, внутрипроцессном sqlite, отдельной таблице БД или даже на собственном сервере, чтобы сохранить входящее необработанное событие и атрибуты, а другой процесс (запланированная задача, служба Windows и т. д.) проанализируйте эту очередь в любом предпочтительном формате, настроенном для быстрых SMTP. Оптимальный ввод, оптимальный вывод, готовность к масштабированию в любом направлении, все довольны.
-121--4349322-Интересная проблема. Звучит так, будто один из сборщиков мусора плохо работает на вашей конкретной ситуации.
Пытались ли вы изменить используемый сборщик мусора? Существует МНОГО вариантов GC, и выяснение, какие из них оптимальны, кажется, немного черного искусства, но мне интересно, сработает ли для вас базовое изменение.
Я знаю, что существует «сервер» GC, который имеет тенденцию работать намного лучше, чем по умолчанию. Вы используете этот?
Threading GC (который, я считаю, по умолчанию), вероятно, худший для вашей конкретной ситуации, я заметил, что он имеет тенденцию быть гораздо менее агрессивным, когда машина занята.
Одна вещь, которую я заметил, часто требуется два GC, чтобы убедить Java на самом деле вынуть мусор. Я думаю, что первый имеет тенденцию разъединять кучу объектов, а второй фактически удаляет их. Возможно, вы захотите иногда принудительно собрать два мусора. Это вызовет значительную паузу GC, но я никогда не видел случая, когда потребовалось больше двух, чтобы очистить всю кучу.
У меня была такая же проблема на машинах Solaris, и я решил ее, уменьшив максимальный размер JVM. 32-битная реализация Solaris, очевидно, нуждается в некотором дополнительном пространстве сверх того, что вы выделяете для JVM при выполнении сборки мусора. Так, например, при -Xmx3580M
я получу описанные вами ошибки, но при -Xmx3072M
все будет нормально.
Какого рода OutOfMemoryError вы получаете? Исчерпано ли место в куче или проблема связана с каким-либо другим пулом памяти (Ошибка обычно имеет сообщение с более подробной информацией о ее причине).
Если куча исчерпана и проблема может быть воспроизведена (похоже, что может), я бы прежде всего настроил виртуальную машину на создание дампа кучи при OutOfMemoryErrors. Затем вы можете проанализировать кучу и убедиться, что она не заполнена объектами, которые все еще доступны через неожиданные ссылки.
Конечно, не исключено, что вы столкнулись с ошибкой VM, но если ваше приложение полагается на специфическое поведение реализации в 1.6.0_03, оно может по тем или иным причинам оказаться загрузчиком памяти при работе на 1.6.0_16. Такие проблемы также могут возникнуть, если вы используете какой-либо серверный контейнер для своего приложения. Некоторые разработчики, очевидно, не умеют читать документацию, но склонны наблюдать за поведением API и делать собственные выводы о том, как что-то должно работать. Это, конечно, не всегда правильно, и я сталкивался с подобными проблемами как с Tomcat, так и с JBoss (оба продукта, по крайней мере, раньше работали только с определенными виртуальными машинами).
Также убедитесь, что это не аппаратная ошибка (попробуйте запустить MemTest86 или что-то подобное на сервере)
.С какими именно ошибками SIGSEV вы сталкиваетесь?
Если вы используете 32-битную VM, это может быть то, что я описал здесь: http://janvanbesien.blogspot.com/2009/08/mysterious-jvm-crashes-explained.html
Для решения этих проблем, я думаю, вам нужно иметь возможность воспроизвести их в контролируемой среде, где вы можете точно продублировать прогоны с различными параметрами настройки и/или изменениями кода. Если вы не можете этого сделать, то наем эксперта, вероятно, не принесет вам никакой пользы, а самым дешевым способом решения проблемы, вероятно, будет покупка большего объема оперативной памяти.