我展示了使用 perf -g -p
收集的样本的 perf 报告
的输出。我不知道如何实现第一列。有很多 Java_*
调用花费了超过 90% 的时间。
在呈现的结果中有很多条目,我的意思是:
+ 98,78% 0,00% java libpthread-2.26.so
+ 95,77% 0,00% java libjvm.so
...
我的问题是:
为什么这样的条目多于 1 个?每个条目都是一种堆栈跟踪。单线程进程只有一个堆栈跟踪。
最佳答案
您在此处引用的列表:
+ 98,78% 0,00% java libpthread-2.26.so + 95,77% 0,00% java libjvm.so
...
And my question is:
Why is there more such entries than 1? Every entry is a kind of stacktrace. The one-threaded process has exactly one stacktrace.
不是堆栈跟踪吗?它是运行期间任何示例的任何堆栈跟踪中出现的函数列表。仅当您展开该列表的一个元素时,您才能看到包含该函数的堆栈跟踪的组合 TreeView 。
我不确定你的意思单线程进程只有一个堆栈跟踪。任何进程在其生命周期内都会有各种堆栈跟踪,即使它只有一个线程。例如,在启动时,堆栈跟踪将只是 main()
,并且尽快 main()
调用函数,堆栈跟踪会更改以包含该函数等等。
现在在函数列表中,第一列显示总开销,包括所有子函数(即,包括此函数调用的函数)。由于几乎所有有趣的工作都发生在共享相同最外层函数的调用链中,因此顶层是一种无用的列表,其中显示的许多函数的开销超过 90%。
第二列是“自己的”开销,这意味着在该方法中实际花费的时间1,不是任何子方法。对于所有顶级方法来说,该值接近于零,因此真正的工作发生在这些方法调用的某些方法中,而不是这些方法本身。
您在顶部展开的 TreeView 确实告诉您需要了解的内容:~94% 的时间花在 radek.queue.wlQueue.writeBytes()
的内部/下面。 ,而那个家伙大部分时间都花在 String.intern()
上。 。所以这里的瓶颈是所有String.intern()
调用,可能是因为字符串表太小,或者只是因为 String.intern()
只是generally sucks用于重复数据删除。我这里的一般规则是使用 Guava 的 Interner<String>
除非您特别需要文字字符串与内部字符串共享相同字符串池的属性(即 "foo" == new String("foo").intern()
)。
1 我在这里宽松地说“时间量” - 它实际上是您指定给 perf record
的任何事件的总样本的分数。 - 但默认情况下,这应该大约是 CPU 时间。
关于perf - 性能报告解读,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48957480/