为什么java String.contains 没有使用类似KMP字符串匹配算法进行优化?
5 个回答
这要找到最正确的答案恐怕得去问问Java的元老们才行⋯任何其他人的“分析”都只能是猜测。
毕竟这块代码(String.indexOf(String))的实现从Sun JDK 1.0.2开始到现在的Oracle JDK8u一直都没怎么变过;只有少量细节变了点,算法思路完全没变。
从以下两个OpenJDK邮件列表的讨论串看,最大的可能是“还没优化到这里”和“常用场景下这个实现已经很快,外加这个实现不需要额外空间开销”。
Inefficient code of String.indexOf(String)String.indexOf optimization结论是:欢迎提交改进的patch;“你行你上”系列。
注意:新的“优化”实现必须要在“常用场景”上能比当前实现有显著性能提升,而且额外空间开销不会很大,才有可能被接受。KMP在“常用场景”上未必能做到这点:初始化的时间开销、额外的空间开销都会成为绊脚石。
所谓“常用场景”,Java里大多数String的长度其实并不长。有兴趣的话可以跑一个您的应用场景里的典型应用统计一下长度。
另外题主肯定没有关注的是,虽然OpenJDK的String.indexOf()的源码写成那样,在许多JVM里这个方法都有内部的特定优化——JVM直接无视原本Java版的实现,而在内部重新实现一遍。
Oracle JDK / OpenJDK的HotSpot VM就会做这样的优化,例如在有SSE4.2指令的x86上会用SSE4.2的STTNI系指令pcmpestri来实现String.indexOf()。我在这里放过一个笔记:
https://gist.github.com/rednaxelafx/1899882我相信IBM J9 VM的Testarossa JIT编译器也有类似的优化。
这样任凭别人怎么修改Java版的实现,等到被JIT编译之后都无所谓了⋯
所以如果题主有兴趣提交patch给OpenJDK去改进String.indexOf()的性能,请记住要用参数
-XX:DisableIntrinsic=_indexOf
来测试。不然无论您怎么改Java代码最后跑的搞不好都是一样的东西。
KMP的O(n)在实际应用并不那么理想,
平均性能大都比不上Boyer-Moore 或 简化的 horspool算法,
facebook 的folly库就采用Boyer-Moore算法,
不过与KMP类似的Aho-Corasick在压缩空间后还是很可观的。
Snort初期采用的是Aho-Corasick,但现在好像改用wu-manber了,太久没关注了。
若想深入了解,可以去查阅这本书<< 柔性字符串匹配 >>