【发布时间】:2016-09-02 15:28:44
【问题描述】:
我不是第一次遇到这个问题。
我通过查看 Java Mission Control 中的 Flight Recorder 记录来优化我的 Scala / Java 代码。查看最热门的方法,然后是内存分配,最终应用程序的运行速度提高了 50 倍或 3 倍。
当我达到这一点时,CPU 使用率为 60-90%,内存使用量是最大 4GB 堆中的 2GB。但我认为我可以提高速度。
特点:
- 单线程处理,从文件系统中读取单个文件。
- 文件系统读取速度为 1GB/s,但处理速度低至 5MB/s(分支、状态机等)的顺序读取。
- 尽可能减少垃圾收集。
- 没有花哨的库,只有纯 JVM 代码。
代码大致如下(伪代码):
for line in file // using an iterator which would call into a file
result = process_line(line)
state = state.process(result)
if state.emits:
println(state.result)
在一个应用程序中,我有以下最热门的方法:
scala.collection.immutable.HashMap$HashTrieMap.getO(Object, Int, Int) 6.75%
java.io.BufferedInputStream.read() 4.97%
在另一个(这不是我的想法):
(some sort of garbage collection process) 9%
... 7%
还值得优化这些吗?我已经尝试过,但对于更复杂的代码,性能几乎没有提升。
接下来我应该看哪里?
我是否应该考虑在一个线程上执行process_line(),然后在另一个线程上迭代状态以最小化上下文切换?也许这就是让事情变慢的原因?
什么是正确的方法?我还不想将问题本身并行化。
【问题讨论】:
-
我会专注于你花费最多时间使用 CPU 的地方,看看你是否可以优化它或将工作传递给另一个线程。 IE。你正朝着正确的方向前进,你需要不断优化。
-
我更新了问题以包含更多细节。没有“最热门”的方法,有一堆来自不同软件包的使用大致相似数量的 CPU。
-
我会怀疑像你这样的排序集合,看看你是否可以在没有它的情况下编写代码。 BufferedInputStream.read() 不应该那么昂贵,因为理想情况下它应该一次读取阻塞字节,但这取决于你为什么这样做。我会看看有多少方法是“噪音” esp 收集操作,而不是你的应用程序的核心逻辑。
-
如果您担心上下文切换的成本,您应该对其进行衡量。以及其他操作系统级别的统计信息以及它们。既然你在做 println,你有没有试过重定向到
/dev/null? -
@the8472 不打印任何输出会产生 8% 的性能提升。您将如何测量 Mac / Linux 上的此类上下文切换?
标签: java performance scala optimization jvm