Guava Charmatcher静态初始化缓慢

更新:看起来我的13.0.1正在调用来自这个差异化CharMatcher的代码。

http://code.google.com/p/guava-libraries/source/diff?spec=svn69ad96b719d7cd3d872a948d7454f17b816a21c2&r=464b0cfab7c3b6713c35e6f3ae7426542668c77b&format=side&path=/guava/src/com/google/common/base/CharMatcher.java

我似乎遇到了番石榴的Charmatcher的问题。 我目前正在编写一些JUnit测试,我注意到第一次测试花费了一些时间(15+秒),但未来的测试大致相同(.3秒),大多数测试都在同一个测试中运行码。

我对代码的分析表明,Guava图书馆中的Charmatcher似乎是罪魁祸首。 看起来CharMatcher中有一些静态初始化代码可能是它花费这么长时间的真正原因。 有什么办法可以禁用或优化这种行为吗? 维基页面或帮助文件中是否存在我遗漏的内容?

Guava版本13.0.1,系统:Linux 64,Eclipse 3.6.1

编辑:我用以下代码构建了一个测试应用程序:

import com.google.common.base.CharMatcher; public class Main { public static void main(String[] args) { // Using system instead of stopwatch to isolate library. long startTime = System.currentTimeMillis(); CharMatcher.is(' '); long endTime = System.currentTimeMillis(); System.out.println("took " + String.valueOf(endTime-startTime) + " ms"); startTime = System.currentTimeMillis(); CharMatcher.is('d'); endTime = System.currentTimeMillis(); System.out.println("2nd took " + String.valueOf(endTime-startTime) + " ms"); } } 

这导致以下输出:

 took 15945 ms 2nd took 0 ms 

我在eclipse中运行了这个,而不是JUnit框架和google的guava库。 我还打包了一个可执行的char并收到了类似的结果。 在我通过它运行一个分析器后,我会再回来进行第二次编辑。

谢谢你的帮助。

编辑2:分析结果:

 Main.main(String[]) 22,556 ms com.google.common.base.CharMatcher.() 22.556 ms com.google.common.base.CharMatcher.precomputed() 22,550 ms com.google.common.base.Platform.precomputeCharMatcher(CharMatcher) 22,550 ms com.google.common.base.CharMatcher.precomputedInternal() 22,550 ms com.google.common.base.CharMatcher.slowGetChars() 13,638 ms com.google.common.base.CharMatcher.setBits(CharMatcher$LookupTable) 8,911 ms 

更新:这在Guava 14中得到修复 。

你遇到了某些在u21中存在的JIT错误,可能是早期版本,但至少在一些后来的JDK版本中没有。 这是u21中测试程序的-XX:+ PrintCompilation输出:

  1 java.util.Arrays::binarySearch0 (72 bytes) 2 com.google.common.base.CharMatcher$Or::matches (28 bytes) 3 com.google.common.base.CharMatcher$12::matches (22 bytes) 2 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 4 com.google.common.base.CharMatcher$11::matches (17 bytes) 5 java.util.Arrays::binarySearch (9 bytes) 6 com.google.common.base.CharMatcher$Or::matches (28 bytes) 1% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 6 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 7 com.google.common.base.CharMatcher$Or::matches (28 bytes) 7 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 1% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 2% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 8 com.google.common.base.CharMatcher$Or::matches (28 bytes) 8 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 2% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 3% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 9 com.google.common.base.CharMatcher$Or::matches (28 bytes) 9 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 3% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 4% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 10 com.google.common.base.CharMatcher$Or::matches (28 bytes) 10 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 4% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 11 com.google.common.base.CharMatcher$Or::matches (28 bytes) 5% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 11 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 12 com.google.common.base.CharMatcher$Or::matches (28 bytes) 5% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 12 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 6% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 13 com.google.common.base.CharMatcher$Or::matches (28 bytes) 13 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 6% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 7% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 14 com.google.common.base.CharMatcher$Or::matches (28 bytes) 15 com.google.common.base.CharMatcher::slowGetChars (52 bytes) 14 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 7% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 16 com.google.common.base.CharMatcher$Or::matches (28 bytes) 16 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 17 com.google.common.base.CharMatcher$Or::matches (28 bytes) 17 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 8% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 18 com.google.common.base.CharMatcher$Or::matches (28 bytes) 18 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 19 com.google.common.base.CharMatcher$Or::matches (28 bytes) 19 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 20 com.google.common.base.CharMatcher$Or::matches (28 bytes) 8% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 20 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 21 com.google.common.base.CharMatcher$Or::matches (28 bytes) 21 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 22 com.google.common.base.CharMatcher$Or::matches (28 bytes) 9% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 22 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 23 com.google.common.base.CharMatcher$Or::matches (28 bytes) 23 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 24 com.google.common.base.CharMatcher$Or::matches (28 bytes) 24 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 9% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 25 com.google.common.base.CharMatcher$Or::matches (28 bytes) 25 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 26 com.google.common.base.CharMatcher$Or::matches (28 bytes) 26 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 10% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 27 com.google.common.base.CharMatcher$Or::matches (28 bytes) 27 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 28 com.google.common.base.CharMatcher$Or::matches (28 bytes) 28 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 10% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 29 com.google.common.base.CharMatcher$Or::matches (28 bytes) 29 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 30 com.google.common.base.CharMatcher$Or::matches (28 bytes) 30 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 11% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 31 com.google.common.base.CharMatcher$Or::matches (28 bytes) 31 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 32 com.google.common.base.CharMatcher$Or::matches (28 bytes) 32 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 11% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 33 com.google.common.base.CharMatcher$Or::matches (28 bytes) 33 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 34 com.google.common.base.CharMatcher$Or::matches (28 bytes) 34 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 35 com.google.common.base.CharMatcher$Or::matches (28 bytes) 12% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 35 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 36 com.google.common.base.CharMatcher$Or::matches (28 bytes) 36 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 37 com.google.common.base.CharMatcher$Or::matches (28 bytes) 37 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 12% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 38 com.google.common.base.CharMatcher$Or::matches (28 bytes) 38 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 39 com.google.common.base.CharMatcher$Or::matches (28 bytes) 39 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 13% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 40 com.google.common.base.CharMatcher$Or::matches (28 bytes) 40 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 41 com.google.common.base.CharMatcher$Or::matches (28 bytes) 41 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 13% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 42 com.google.common.base.CharMatcher$Or::matches (28 bytes) 42 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 43 com.google.common.base.CharMatcher$Or::matches (28 bytes) 43 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 44 com.google.common.base.CharMatcher$Or::matches (28 bytes) 14% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 44 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 45 com.google.common.base.CharMatcher$Or::matches (28 bytes) 45 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 46 com.google.common.base.CharMatcher$Or::matches (28 bytes) 46 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 14% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 47 com.google.common.base.CharMatcher$Or::matches (28 bytes) 47 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 48 com.google.common.base.CharMatcher$Or::matches (28 bytes) 48 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 15% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 49 com.google.common.base.CharMatcher$Or::matches (28 bytes) 49 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 50 com.google.common.base.CharMatcher$Or::matches (28 bytes) 50 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 15% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 51 com.google.common.base.CharMatcher$Or::matches (28 bytes) 51 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 52 com.google.common.base.CharMatcher$Or::matches (28 bytes) 52 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 16% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 53 com.google.common.base.CharMatcher$Or::matches (28 bytes) 53 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 54 com.google.common.base.CharMatcher$Or::matches (28 bytes) 54 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 16% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 55 com.google.common.base.CharMatcher$Or::matches (28 bytes) 55 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 56 com.google.common.base.CharMatcher$Or::matches (28 bytes) 56 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 57 com.google.common.base.CharMatcher$Or::matches (28 bytes) 17% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 57 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 58 com.google.common.base.CharMatcher$Or::matches (28 bytes) 58 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 59 com.google.common.base.CharMatcher$Or::matches (28 bytes) 59 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 17% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 60 com.google.common.base.CharMatcher$Or::matches (28 bytes) 60 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 61 com.google.common.base.CharMatcher$Or::matches (28 bytes) 61 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 18% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 62 com.google.common.base.CharMatcher$Or::matches (28 bytes) 62 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 63 com.google.common.base.CharMatcher$Or::matches (28 bytes) 63 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 18% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 64 com.google.common.base.CharMatcher$Or::matches (28 bytes) 64 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 65 com.google.common.base.CharMatcher$Or::matches (28 bytes) 65 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 19% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 66 com.google.common.base.CharMatcher$Or::matches (28 bytes)  143% made not entrant com.google.common.base.CharMatcher::setBits @ -2 (30 bytes) 144% com.google.common.base.CharMatcher::setBits @ 2 (30 bytes) 144% made not entrant com.google.common.base.CharMatcher::setBits @ -2 (30 bytes) 145% com.google.common.base.CharMatcher::setBits @ 2 (30 bytes) 145% made not entrant com.google.common.base.CharMatcher::setBits @ -2 (30 bytes) took 7599 ms 2nd took 0 ms 

这是u34的相同输出:

  64 1 java.util.Arrays::binarySearch0 (72 bytes) 68 2 com.google.common.base.CharMatcher$Or::matches (28 bytes) 68 3 com.google.common.base.CharMatcher$12::matches (22 bytes) 70 4 com.google.common.base.CharMatcher$11::matches (17 bytes) 71 5 java.util.Arrays::binarySearch (9 bytes) 71 1% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 76 2 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 76 6 com.google.common.base.CharMatcher$Or::matches (28 bytes) 88 1% made not entrant com.google.common.base.CharMatcher::slowGetChars @ -2 (52 bytes) 88 6 made not entrant com.google.common.base.CharMatcher$Or::matches (28 bytes) 88 7 com.google.common.base.CharMatcher::slowGetChars (52 bytes) 89 8 com.google.common.base.CharMatcher$Or::matches (28 bytes) 91 9 com.google.common.base.CharMatcher$8::matches (14 bytes) 91 2% com.google.common.base.CharMatcher::slowGetChars @ 9 (52 bytes) 98 10 java.lang.String::indexOf (166 bytes) 98 11 java.lang.String::indexOf (151 bytes) 102 3% com.google.common.base.CharMatcher::setBits @ 2 (30 bytes) 113 12 com.google.common.base.CharMatcher::setBits (30 bytes) 113 13 com.google.common.base.CharMatcher$LookupTable::set (15 bytes) 

正如你所看到的,在u34中,这是一个更加理智的地狱。 看起来在u21中发生的是OSR的一些组合(影响slowGetChars方法,因为它有一个大循环),以及递归的变形调用(影响CharMatcher$OrCharMatcher其他子类 – 在递归结束时调用CharMatcher$Or chain)产生了JIT去优化和随后重新编译的完美风暴,这在u34中得到了解决。

尽管如此,我认为Guava家伙在静态初始化期间创建一个65k元素的LUT有点滥用,即使你从未使用过相关的匹配器,当JIT工作正常时它仍需要大约50ms。 我提交了一个针对番石榴的bug ,让我们看看维护者是否同意:)。 更新:在我提交此文件的几天内修复了该错误,修复程序将在Guava 14中。这就是我所说的快速周转!

原帖如下:

我有完全相同的行为,并在这篇文章中寻找解决方案。

查看代码,看起来他们正在创建一个65k元素(每个元素占用一位)查找表并检查每个字符是否匹配,这需要许多嵌套函数调用,因为使用了流畅的样式来定义匹配器:

  public static final CharMatcher INVISIBLE = inRange('\u0000', '\u0020') .or(inRange('\u007f', '\u00a0')) .or(is('\u00ad')) .or(inRange('\u0600', '\u0604')) .or(anyOf("\u06dd\u070f\u1680\u180e")) .or(inRange('\u2000', '\u200f')) .or(inRange('\u2028', '\u202f')) .or(inRange('\u205f', '\u2064')) .or(inRange('\u206a', '\u206f')) .or(is('\u3000')) .or(inRange('\ud800', '\uf8ff')) .or(anyOf("\ufeff\ufff9\ufffa\ufffb")) .withToString("CharMatcher.INVISIBLE") .precomputed(); 

这是触发长静态初始化的代码,在我的快速框中需要约7秒。 这是我的盒子上你的应用程序的输出:

 took 6814 ms 2nd took 0 ms 

我正在提起一个番石榴虫。

作为快速帮助,请尝试从源代码库切换到最新版本。 那里有变化,例如slowGetChars方法消失了 。 它曾经有点慢,但远不及你发生的事情。

对于其他所有人来说,它的运行速度要快几百倍而且无法重现它很难提供帮助。

刚试过:

 @Test public void testCharMatcherSlow() throws Exception { System.out.println(CharMatcher.JAVA_DIGIT.matches('1')); } 

并且执行需要0.06秒。 还查看了CharMatcher代码,没有什么可以解释您遇到的缓慢行为。 您应该通过模拟替换CharMatcher以查看它不是问题,并且可能使用分析器来查找原因。

我刚刚运行了你提供的确切基准,并得到了

花了74毫秒

第二次花了0毫秒

……问题可能在于Eclipse的结尾? 你在调试模式下运行吗?