当前位置: 首页 > 面试题库 >

用于确定JVM何时进入内存/ GC故障的有用度量

李奕
2023-03-14
问题内容

我有一个scala数据处理应用程序,该应用程序有95%的时间可以处理内存中抛出的数据。剩下的5%(如果不加以检查)通常不会遇到
OutOfMemoryError
,而只是进入主要GC的周期,这会导致CPU峰值运行,阻止后台线程执行,并且即使完成也要花费10x-50x的时间有足够的内存。

我已经实现了可以将数据刷新到磁盘并将磁盘流视为内存迭代器的系统。它通常比内存慢一个数量级,但足以应付这5%的情况。我当前是由集合上下文的最大大小的启发式触发的,该上下文跟踪数据处理中涉及的各种集合的大小。这是可行的,但实际上只是一个预设的经验阈值。

我宁愿对JVM接近上述不良状态并在那时刷新到磁盘做出反应。我曾尝试观察记忆,但找不到正确的伊甸园,旧酒等组合来可靠地预测死亡螺旋。我还尝试过仅查看主要GC的频率,但是似乎也受制于从“太保守”到“太晚”的范围。

任何用于判断JVM健康状况和检测故障状态的资源将不胜感激。


问题答案:

一种可靠的方法是在GC事件上注册通知侦听器,并在所有Full
GC事件发生后检查内存运行状况。在发生完全GC事件后,直接使用的内存就是您实际的实时数据集。如果此时您的可用内存不足,则可能是时候开始向磁盘移动。

这样,您可以避免在不知道何时发生完整GC的情况下(例如在使用MEMORY_THRESHOLD_EXCEEDED通知类型时)尝试检查内存时经常发生的误报。

您可以使用以下代码注册通知侦听器并处理Full 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.
                    }
                }
            }
        }
    };
}

相信这篇文章是我们最初提出这个想法的。



 类似资料:
  • 主要内容:一、业务场景介绍,二、问题凸现,三、定位问题,四、解决问题这篇文章给大家聊一次线上生产系统事故的解决经历,其背后代表的是线上生产系统的JVM FullGC可能引发的严重故障。 一、业务场景介绍 先简单说说线上生产系统的一个背景,因为仅仅是文章作为案例来讲,所以弱化大量的业务背景。 简单来说,这是一套分布式系统,系统A需要将一个非常核心以及关键的数据通过网络请求,传输给另外一个系统B。 所以这里其实就考虑到了一个问题,如果系统A刚刚将核心数据传递给了系统B

  • 我目前正在运行一个长时间运行的JVM应用程序(其中包括groovy类),我观察到了一些奇怪的行为。 我运行了应用程序并更新了我的Groovy类(正确地清理了元类信息等--我知道没有泄漏),所以我知道有几个类可以从permgen收集(通常我观察到permgen没有被急切地收集--我相信只是完整的GC收集了permgen,所以对于这种状态并不罕见)。奇怪的是,如果我让应用程序在没有activity的情

  • 我试图设置一个带有前端pod(cup fe)和后端pod的GKE环境,用于在登录时对用户进行身份验证(cup auth),但我无法让我的入口正常工作。 以下是运行nginx的前端吊舱(cup fe),带有角度应用程序。我还创建了一个静态IP地址,由“cup.xxx.it”和“cup-auth.xxx.it”dns解析: 然后是认证盒(cup auth): 然后,我创建了两个节点报告来公开上述POD

  • 问题内容: jvm进程的内存使用量一直在增加,并且从未减少。我通过在linux服务器上执行top进行检查。该应用程序正在将作业调度到群集(使用Quartz + SunJava DRMAA API) Java堆空间在应用程序生命周期内保持在限制之内,但是jvm进程显示内存使用率稳定增长且从未下降。 这是内存泄漏吗?如果是这样,为什么堆空间在限制之内。有人可以解释一下。 更新: 当我通过jconsol

  • 故障注入配置参考。 filter.http.FaultAbort filter.http.FaultAbort proto { "percent": "...", "http_status": "..." } percent (uint32) 一个介于0到100之间的整数,表示请求/操作/连接通过下面的状态码中止的百分比。 http_status (uint32) 用于中止HTTP请求的

  • 故障注入配置概述。 Configuration { "name" : "fault", "config" : { "abort" : "{...}", "delay" : "{...}", "upstream_cluster" : "...", "headers" : [], "downstream_nodes" : [] } } abort