Java 记录线取10';毫秒数

Java 记录线取10';毫秒数,java,performance,logging,Java,Performance,Logging,在某些情况下,在以下代码中调用java.util.logging.Logger.log()时,我发现延迟非常高: private static Object[]NETWORK\u LOG\u TOKEN=new Object[]{Integer.valueOf(1)}; private final TimeProbe_u2;=新TimeProbe(); 接收到公共void ontextmessages(ArrayList msgs_列表){ final long start_ts=probe_u

在某些情况下,在以下代码中调用java.util.logging.Logger.log()时,我发现延迟非常高:

private static Object[]NETWORK\u LOG\u TOKEN=new Object[]{Integer.valueOf(1)};
private final TimeProbe_u2;=新TimeProbe();
接收到公共void ontextmessages(ArrayList msgs_列表){
final long start_ts=probe_u.addTs();//探测A
//循环浏览消息
用于(字符串消息:msgs\U列表){
probe_uz.addTs();//探测B
log.log(Level.INFO,要尝试的内容:

  • 启用JVM安全点日志。VM暂停为

  • 如果您使用JDK<15,请禁用偏置锁定:
    -XX:-UseBiasedLocking
    。JUL framework中有许多
    已同步的
    位置。在多线程应用程序中,这可能会导致偏置锁撤销,这是safepoint暂停的常见原因

  • 使用.jfr输出在挂钟模式下运行。然后,使用JMC,您将能够找到线程在给定时间点附近到底在做什么

  • 尝试将日志文件放到tmpfs上以排除磁盘延迟,或者使用
    MemoryHandler
    而不是
    FileHandler
    检查文件I/O是否会影响暂停

  • 尝试的事项:

  • 启用JVM安全点日志。VM暂停为

  • 如果您使用JDK<15,请禁用偏置锁定:
    -XX:-UseBiasedLocking
    。JUL framework中有许多
    已同步的
    位置。在多线程应用程序中,这可能会导致偏置锁撤销,这是safepoint暂停的常见原因

  • 使用.jfr输出在挂钟模式下运行。然后,使用JMC,您将能够找到线程在给定时间点附近到底在做什么

  • 尝试将日志文件放到tmpfs上以排除磁盘延迟,或者使用
    MemoryHandler
    而不是
    FileHandler
    检查文件I/O是否会影响暂停

  • 除了B和C之间的代码行(在for循环的第一次迭代过程中)需要73毫秒的时间外,所有的时间都不到1毫秒。[snip]…但我仍然想不出为什么有时候,第一个日志行需要永远的时间

    发布到根记录器或其处理程序的第一条日志记录将 是的

    如果不需要发布到根日志记录器处理程序,则在添加文件处理程序时调用。这将使日志记录不会传播到根日志记录器。它还确保不会发布到连接到父日志记录器的其他处理程序

    在开始循环之前,您还可以通过执行
    Logger.getLogger(“”.getHandlers()
    )加载根处理程序。加载它们的代价是在不同的时间

    日志\日志(Level.INFO,“ 除了B和C之间的代码行(在for循环的第一次迭代过程中)需要73毫秒的时间外,所有的时间都不到1毫秒。[snip]…但我仍然想不出为什么有时候,第一个日志行需要永远的时间

    发布到根记录器或其处理程序的第一条日志记录将 是的

    如果不需要发布到根日志记录器处理程序,则在添加文件处理程序时调用。这将使日志记录不会传播到根日志记录器。它还确保不会发布到连接到父日志记录器的其他处理程序

    在开始循环之前,您还可以通过执行
    Logger.getLogger(“”.getHandlers()
    )加载根处理程序。加载它们的代价是在不同的时间


    日志(Level.INFO,"这是唯一需要这么长时间的日志语句吗?这对于配置中的日志语句来说是不寻常的吗?您如何知道这是日志记录,而不是您将ts添加到arraylist的方式?运行这10k次,看看它是否稳定下来如何?这可能与jit或其他优化在l开始时启动有关oop当它意识到您将要循环时,这种效果将在数千次运行中消除。一般来说,您不能只运行一次代码,就期望配置文件合理或准确。您是否查看过
    System.currentTimeMillis()的粒度
    在您的系统上?如果这种情况很少见,可能是NTP同步,请尝试使用
    nanoTime()
    来代替。可能有一百万种情况,请尝试使用并查看其输出。如果没有显示任何内容,当然可能是记录器在IO上被阻塞(写入其缓冲区),使用探查器确认。这是唯一需要这么长时间的日志语句吗?这对于配置中的日志语句来说是不寻常的吗?您如何知道这是日志记录,而不是您将ts添加到arraylist的方式?运行这10k次,看看它是否稳定下来如何?这可能与jit或其他优化有关在循环开始时,当它意识到您将要循环时,这种效果将在数千次运行中消除。一般来说,您不能一次运行代码就期望配置文件合理或准确。您是否查看了
    System.currentTimeMillis()的粒度
    在您的系统上?如果这种情况很少见,可能是NTP同步,请尝试使用
    nanoTime()
    来代替。可能有一百万种情况,请尝试使用并查看其输出。如果没有显示任何内容,当然可能是记录器在IO上被阻塞(写入其缓冲区),使用探查器进行确认。谢谢@apangin,我一直在使用异步探查器,但我还没有弄清楚如何查看特定线程在特定时间正在执行的操作。在jmc中查看jfr输出给了我一些有趣的信息,但即使是thread选项卡似乎也没有给我足够的粒度信息来查看线程正在执行的操作“在给定的时间内正在运行。@MarkoPaulo您可以使用JMC中的事件浏览器菜单列出所有方法。”
    log_.log(Level.INFO, msg, NETWORK_LOG_TOKEN);
    
    public Foo {
       private static final String CLASS_NAME = Foo.class.getName();
       private static final Logger log_ = Logger.getLogger(CLASS_NAME);
    
       public void onTextMessagesReceived(ArrayList<String> msgs_list) {
           String methodName = "onTextMessagesReceived";
           // Loop through the messages
           for (String msg: msgs_list) {
              probe_.addTs(); // probe B
              log_.logp(Level.INFO, CLASS_NAME, methodName, msg, NETWORK_LOG_TOKEN);
              probe_.addTs(); // probe C
    
              // Do some work on the message ...
              probe_.addTs(); // probe D
          }
       }
    }