C2编译器在启动时使CPU占用过高

6
我有一个 Java 7 的 Java Servlet 应用程序,通常在系统资源消耗方面非常健康。 通常情况下,服务器上的 CPU 使用率低于 50%。 然而,在启动后的几分钟内,它的行为会有很大不同,如果在此期间尝试服务大量流量,则 CPU 可以被固定在 100% 多达数分钟。 结果是响应时间变慢,网络超时甚至长时间的垃圾回收暂停。
为了诊断问题,我在服务器启动时进行了一系列线程转储,并同时运行了 top -H 命令。 通过将每个 Java 线程与 pid 匹配,我可以始终看到 C2 CompilerThread 使用最多的 CPU。 我已经研究了这个线程的作用,并且我知道它是一个基于运行时统计信息优化代码的 Java 编译器。 但是从我所做的所有阅读中,我无法确定使情况变得更好的最佳方法。 我能得出的唯一选项是:
1. 从 C2 切换到 TieredCompiler(但这是否会导致启动后的前几分钟性能更好?) 2. 打开 -XX:+PrintCompilation 以查看正在进行的优化(但我该如何处理这些信息?我能否在服务器接受流量之前强制进行优化?)
应该采取什么最佳方法,还有其他选项可以尝试以缓解启动后的 CPU 使用情况吗?

2
一旦你找到了所有代码编译的位置,看看如何减少它。这可能意味着删除一个特别昂贵的库。在我看来,拥有让C2花费长时间编译的大量代码并不正常。 - Peter Lawrey
谢谢。我尝试了一下,但不确定我在寻找什么。只是最常编译的方法?还是标记为“made zombie”或“made not entrant”的方法?对我来说没有显而易见的东西。 - Cameron
哪些软件包编译了最多的方法,即这个JAR文件来自哪里? - Peter Lawrey
也许C2会耗尽内存,不得不丢弃已编译的方法并一遍又一遍地重新编译它们?这只是根据在某个相关讨论中看到的猜测。也许这个答案可以帮助? - maaartinus
2个回答

1
有几种付费JVM技术可用于通过预编译来缓解您的问题。
但是,如果您想坚持使用标准JVM,人们使用的一个技巧是在启动后发送几个虚拟请求,以便在实际操作开始之前使JVM热身。这样,您可以决定何时在为客户提供服务之前支付JVM热身成本。
您还可以通过Hotspot的-Xcomp命令行选项强制JVM编译所有代码,但我们不建议这样做,因为它会通过编译很少使用的代码来减慢应用程序的启动速度。

0
我在第一次调用instrumentation.retransformClasses(clazz);后遇到了同样的问题。instrumentation是关于Java代理的java.lang.instrument类。
下面是从JDK源代码中retransformClasses所做的事情。
    /**
     * Retransform the supplied set of classes.
     *
     * <P>
     * This function facilitates the instrumentation
     * of already loaded classes.
     * When classes are initially loaded or when they are
     * {@linkplain #redefineClasses redefined},
     * the initial class file bytes can be transformed with the
     * {@link java.lang.instrument.ClassFileTransformer ClassFileTransformer}.
     * This function reruns the transformation process
     * (whether or not a transformation has previously occurred).
     * This retransformation follows these steps:
     *  <ul>
     *    <li>starting from the initial class file bytes
     *    </li>
     *    <li>for each transformer that was added with <code>canRetransform</code>
     *      false, the bytes returned by
     *      {@link java.lang.instrument.ClassFileTransformer#transform transform}
     *      during the last class load or redefine are
     *      reused as the output of the transformation; note that this is
     *      equivalent to reapplying the previous transformation, unaltered;
     *      except that
     *      {@link java.lang.instrument.ClassFileTransformer#transform transform}
     *      is not called
     *    </li>
     *    <li>for each transformer that was added with <code>canRetransform</code>
     *      true, the
     *      {@link java.lang.instrument.ClassFileTransformer#transform transform}
     *      method is called in these transformers
     *    </li>
     *    <li>the transformed class file bytes are installed as the new
     *      definition of the class
     *    </li>
     *  </ul>
     * <P>
     *
     * The order of transformation is described in the
     * {@link java.lang.instrument.ClassFileTransformer#transform transform} method.
     * This same order is used in the automatic reapplication of retransformation
     * incapable transforms.
     * <P>
     *
     * The initial class file bytes represent the bytes passed to
     * {@link java.lang.ClassLoader#defineClass ClassLoader.defineClass} or
     * {@link #redefineClasses redefineClasses}
     * (before any transformations
     *  were applied), however they might not exactly match them.
     *  The constant pool might not have the same layout or contents.
     *  The constant pool may have more or fewer entries.
     *  Constant pool entries may be in a different order; however,
     *  constant pool indices in the bytecodes of methods will correspond.
     *  Some attributes may not be present.
     *  Where order is not meaningful, for example the order of methods,
     *  order might not be preserved.
     *
     * <P>
     * This method operates on
     * a set in order to allow interdependent changes to more than one class at the same time
     * (a retransformation of class A can require a retransformation of class B).
     *
     * <P>
     * If a retransformed method has active stack frames, those active frames continue to
     * run the bytecodes of the original method.
     * The retransformed method will be used on new invokes.
     *
     * <P>
     * This method does not cause any initialization except that which would occur
     * under the customary JVM semantics. In other words, redefining a class
     * does not cause its initializers to be run. The values of static variables
     * will remain as they were prior to the call.
     *
     * <P>
     * Instances of the retransformed class are not affected.
     *
     * <P>
     * The retransformation may change method bodies, the constant pool and attributes.
     * The retransformation must not add, remove or rename fields or methods, change the
     * signatures of methods, or change inheritance.  These restrictions maybe be
     * lifted in future versions.  The class file bytes are not checked, verified and installed
     * until after the transformations have been applied, if the resultant bytes are in
     * error this method will throw an exception.
     *
     * <P>
     * If this method throws an exception, no classes have been retransformed.
     * <P>
     * This method is intended for use in instrumentation, as described in the
     * {@linkplain Instrumentation class specification}.
     *
     * @param classes array of classes to retransform;
     *                a zero-length array is allowed, in this case, this method does nothing
     * @throws java.lang.instrument.UnmodifiableClassException if a specified class cannot be modified
     * ({@link #isModifiableClass} would return <code>false</code>)
     * @throws java.lang.UnsupportedOperationException if the current configuration of the JVM does not allow
     * retransformation ({@link #isRetransformClassesSupported} is false) or the retransformation attempted
     * to make unsupported changes
     * @throws java.lang.ClassFormatError if the data did not contain a valid class
     * @throws java.lang.NoClassDefFoundError if the name in the class file is not equal to the name of the class
     * @throws java.lang.UnsupportedClassVersionError if the class file version numbers are not supported
     * @throws java.lang.ClassCircularityError if the new classes contain a circularity
     * @throws java.lang.LinkageError if a linkage error occurs
     * @throws java.lang.NullPointerException if the supplied classes  array or any of its components
     *                                        is <code>null</code>.
     *
     * @see #isRetransformClassesSupported
     * @see #addTransformer
     * @see java.lang.instrument.ClassFileTransformer
     * @since 1.6
     */
    void
    retransformClasses(Class<?>... classes) throws UnmodifiableClassException;


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接