Полезный показатель для определения того, когда JVM собирается попасть в память/GC-проблема
У меня есть приложение для обработки данных scala, которое 95% времени может обрабатывать данные, брошенные в него в памяти. Остальные 5%, если их не остановить, обычно не попадают в OutOfMemoryError, а просто попадают в цикл основных GC, который всплескивает процессор, предотвращает выполнение фоновых потоков и, если он даже заканчивается, занимает 10x-50x, если он имеет достаточно памяти.
Я реализовал систему, которая может сбрасывать данные на диск и обрабатывать поток диска, как если бы он был итератором в памяти. Он обычно на порядок медленнее памяти, но достаточно для этих 5% случаев. В настоящее время я запускаю эвристику максимального размера контекста коллекции, который отслеживает размер различных коллекций, участвующих в обработке данных. Это работает, но на самом деле это всего лишь эмпирический порог adhoc.
Я бы скорее отреагировал на JVM, приблизившись к вышеупомянутому плохому состоянию и сбросившись на диск в то время. Я пробовал наблюдать за памятью, но не могу найти правильную комбинацию eden, old и т.д., Чтобы надежно предсказать смертельную спираль. Я также пытался просто наблюдать за частотой основных GC, но, похоже, также страдает от того, что у вас слишком широкий "слишком консервативный", чтобы "слишком поздно".
Будут оценены любые ресурсы для оценки состояния здоровья JVM и выявления проблемных состояний.
Ответы
Ответ 1
Один надежный способ - зарегистрировать прослушиватель уведомлений о событиях GC и проверить работоспособность памяти после всех событий GC. Непосредственно после полного GC-события используемая память представляет собой ваш фактический живой набор данных. Если вы в этот момент времени свободны от свободной памяти, вероятно, время начнет мигать с диском.
Таким образом, вы можете избежать ложных срабатываний, которые часто возникают, когда вы пытаетесь проверить память, не зная, когда произошел полный GC, например, при использовании типа уведомления MEMORY_THRESHOLD_EXCEEDED
.
Вы можете зарегистрировать прослушиватель уведомлений и обрабатывать полные события GC, используя что-то вроде следующего кода:
// ... standard imports ommitted
import com.sun.management.GarbageCollectionNotificationInfo;
public static void installGCMonitoring() {
List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
for (GarbageCollectorMXBean gcBean : gcBeans) {
NotificationEmitter emitter = (NotificationEmitter) gcBean;
NotificationListener listener = notificationListener();
emitter.addNotificationListener(listener, null, null);
}
}
private static NotificationListener notificationListener() {
return new NotificationListener() {
@Override
public void handleNotification(Notification notification, Object handback) {
if (notification.getType()
.equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) {
GarbageCollectionNotificationInfo info = GarbageCollectionNotificationInfo
.from((CompositeData) notification.getUserData());
String gctype = info.getGcAction();
if (gctype.contains("major")) {
// We are only interested in full (major) GCs
Map<String, MemoryUsage> mem = info.getGcInfo().getMemoryUsageAfterGc();
for (Entry<String, MemoryUsage> entry : mem.entrySet()) {
String memoryPoolName = entry.getKey();
MemoryUsage memdetail = entry.getValue();
long memMax = memdetail.getMax();
long memUsed = memdetail.getUsed();
// Use the memMax/memUsed of the pool you are interested in (probably old gen)
// to determine memory health.
}
}
}
}
};
}
Подтвердите эту статью, в которой мы впервые получили эту идею.
Ответ 2
В дополнение к механизмам уведомления MemoryMXBean
, описанным в ссылке @Alla . Вы можете использовать комбинацию слабых ссылок и очередей ссылок. Эта старая, но действительная статья содержит хорошее описание слабых, мягких и phantom ссылок и ссылочных очередей.
Основная идея заключается в создании большого массива (для резервирования памяти), создающего слабую или мягкую ссылку на него, и при этом добавьте его в ссылку очереди. Когда давление памяти вызывает сбор слабосвязанного массива, вы получите резервную память (долгое время вдыхаете в ваше приложение и даете ему время). Попросите поток опросить ссылочную очередь, чтобы определить, когда ваш резерв был собран. Затем вы можете активировать поведение потоковой передачи вашего приложения для завершения задания. SoftReferences более устойчивы к давлению памяти, чем WeakReferences, и делают ваши цели лучше.
Ответ 3
может быть эта ссылка поможет вам http://www.javaspecialists.eu/archive/Issue092.html
В моей MemoryWarningSystem вы добавляете слушатели, реализующие интерфейс MemoryWarningSystem.Listener, с одним методом memoryUsageLow(long usedMemory, long maxMemory)
, который будет вызываться, когда достигнут порог. В моих экспериментах память bean уведомляет нас об этом вскоре после того, как превышен порог использования, но я не смог определить степень детализации. Следует отметить, что слушатель вызывается специальным потоком, называемым потоком детектора низкой памяти, который теперь является частью стандартного JVM.
Каков порог? И какой из многих бассейнов мы должны контролировать? Единственный разумный пул для мониторинга - это теневое поколение (старое пространство). Когда вы устанавливаете размер памяти с -Xmx256m, вы устанавливаете максимальную память, которая будет использоваться в Tenured Generation.