我有一个
Scala数据处理应用程序,95%的时间可以处理在内存中抛出的数据.剩下的5%如果没有被选中,通常不会打到OutOfMemoryError,而是进入一个主要的GC的周期,尖锐的cpu,防止后台线程执行,如果它甚至完成,只要它是10x-50x有足够的记忆力
我已经实现了可以将数据刷新到磁盘的系统,并将其视为内存中的迭代器.这通常比记忆慢一个数量级,但对于这5%的情况来说足够了.我目前正在通过追踪数据处理涉及的各种集合的大小的集合上下文的最大大小的启发式触发.这是有效的,但实际上只是一个独特的经验门槛.
我更愿意对JVM进行接近上述不良状态的反应,并在当时刷新到磁盘.我已经尝试看内存,但找不到正确的eden,old等组合来可靠地预测死亡螺旋.我也试过只是观察主要GC的频率,但是似乎还有一个广泛的“太保守”到“太晚”了.
任何用于判断JVM运行状况和检测故障状态的资源将不胜感激.
解决方法
一种可靠的方法是在GC事件上注册通知侦听器,并在所有Full GC事件之后检查内存健康状况.在完整的GC事件之后,使用的内存是您实际的实时数据集.如果你在这个时间点的空闲内存很低,可能是时间开始闪烁到磁盘.
这样,您可以避免在您无法知道何时完成GC时检查内存,例如使用MEMORY_THRESHOLD_EXCEEDED通知类型时,会发生误报.
// ... 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. } } } } }; }