Это довольно сложная проблема для выяснения. Поскольку я провел некоторое время в системе, чтобы выяснить это и доказать, позвольте мне перечислить сценарий, где это произошло
- Мы застряли с использованием Java 6, в котором не было сжатого сборщика мусора
- Наше приложение делало слишком много GC, в основном коллекция молодого поколения и какая-то большая коллекция старого поколения
- Наш размер кучи был довольно большой - основная проблема (мы сократили, но наше приложение занимало слишком много строк и коллекций)
Проблема, которая проявилась в том, что только один конкретный алгоритм в нашей системе работал медленно; все остальные, которые работали одновременно, работали вполне нормально. Это исключило полный сборщик мусора; Также мы использовали jstat и другие инструменты j ** для проверки GC, дампов потоков + отслеживания журналов GC.
Из дампов потоков jstack, взятых в течение некоторого времени, мы могли понять, какой блок кода действительно замедляется. Так что сомнение упало на фрагментацию кучи.
Чтобы проверить, что я написал простую программу, которая инициализировала два List, один ArrayList и один LinkedList, и добавила операции, вызывающие изменение размера. Этот тест я мог выполнить через дескриптор REST.
Обычно нет большой разницы. Но внутри фрагментированной кучи есть четкая разница во времени; изменение размера большой коллекции с ArrayList становится очень медленным, чем со списком связанных. Эти сроки были записаны, и другого объяснения этому не было, кроме фрагментированной головы.
С Java 7 мы перешли на G1GC вместе с большой работой по настройке и улучшению приложений GC; Здесь сжатие кучи намного лучше, и оно может обрабатывать большие кучи, хотя я предполагаю, что что-нибудь более чем 16-граммовая куча попадет вам в места, которые вы действительно не хотите - GC suckage :)