Java 花在物体上的时间。<;初始化>;(hprof)
我正在分析我的一个应用程序——它是一个构建在Java之上的宏系统。我用它来分析一些基本示例,下面是花费时间最多的20个函数:Java 花在物体上的时间。<;初始化>;(hprof),java,memory,profiling,hprof,Java,Memory,Profiling,Hprof,我正在分析我的一个应用程序——它是一个构建在Java之上的宏系统。我用它来分析一些基本示例,下面是花费时间最多的20个函数: rank self accum count trace method 1 14.73% 14.73% 453 303755 java.lang.Object.<init> 2 9.75% 24.48% 300 303754 java.lang.Object.<init> 3 7.18% 31.66%
rank self accum count trace method
1 14.73% 14.73% 453 303755 java.lang.Object.<init>
2 9.75% 24.48% 300 303754 java.lang.Object.<init>
3 7.18% 31.66% 221 303641 java.lang.Object.<init>
4 6.83% 38.49% 210 303621 java.util.ArrayList.<init>
5 6.76% 45.25% 208 303620 java.util.ArrayList.<init>
6 5.95% 51.20% 183 303833 java.lang.Character.toChars
7 4.55% 55.75% 140 303809 java.lang.Object.<init>
8 4.42% 60.18% 136 303791 java.lang.Object.<init>
9 3.77% 63.95% 116 303756 java.lang.Object.<init>
10 3.64% 67.59% 112 300509 java.lang.Object.<init>
11 2.67% 70.25% 82 303789 java.lang.Object.<init>
12 2.54% 72.79% 78 303790 java.lang.Object.<init>
13 1.69% 74.48% 52 303688 java.lang.Object.<init>
14 1.66% 76.14% 51 303644 java.lang.Object.<init>
15 1.46% 77.60% 45 305935 java.lang.Object.<init>
16 1.40% 79.00% 43 303758 java.lang.Object.<init>
17 1.20% 80.20% 37 305324 java.lang.Object.<init>
18 0.98% 81.18% 30 302559 java.lang.Object.<init>
19 0.62% 81.79% 19 300006 java.util.Arrays.copyOf
20 0.52% 82.31% 16 305214 java.lang.Object.<init>
(JPerfAnal还生成一个倒置的树,其中孩子们是父母的调用者。为了简洁起见,我不复制它,但可以说大约40%的对象。
调用是通过初始化ArrayList
、ParseData
和ParseErrors
进行的)
现在,这并没有真正改变我对这个问题或我的问题的看法。我可以改变算法,使它实例化更少的对象;但目前,我正在寻找一个正交的解决方案。所以:对象池能帮我吗?1)“self”时间几乎总是无用的,因为真正的问题在于调用那些低级方法的代码中——getinclusivetime(self+被调用方)
2) “accum”列甚至更无用,因为它所做的只是将“self”时间相加
其他专栏也没有告诉你任何有用的东西
hprof
进行堆栈跟踪。
你需要的是让这些尽可能深。你不需要太多(与流行的统计错误信息相反),十个可能就足够了。
但是,您确实需要查看它们并理解它们 编辑以响应显示JPerfAnal输出的编辑: a) 看起来堆栈深度只有4。您需要查看尽可能深的堆栈深度。 我不喜欢他们展示输出的方式。 我主要看一下堆栈样本本身。 时间不是真正重要的东西。重要的是发生了什么以及为什么 b) 堆栈示例实际上包含行级信息。因此,它们将指向例程中的精确行,如
parser.ParseData.
,parser.Matcher.parse
,以及parser.ParseErrors.
中发生问题调用的位置。
这将准确地告诉您一直在花费哪些分配,然后您可以决定是否有更好的方法来完成这些分配
我得到的印象是解析器运行数据结构表。
我知道你不想重新设计它,但如果你重新设计它,你会得到更好的性能。
基本上,如果您可以将其表示为递归下降解析器,并且如果语言不经常更改,您可以直接在代码中编写解析器—无需表格—速度将提高10-100倍。简短回答:
花费在对象中的时间。
可能是由于CPU配置文件与堆配置文件一起生成;后者检测所有内存分配,使分配变慢,并使它们出现在CPU配置文件的顶部
长答覆:
我怀疑问题中显示的配置文件是通过同时询问CPU配置文件和堆配置文件生成的。换句话说,它是通过如下操作生成的:
java -agentlib:hprof=heap=sites,cpu=samples,depth=20 MyProg
不幸的是,至少在JVM的内置hprof分析器中,CPU采样在堆分析中是无用的。堆分析检测所有内存分配,使程序的运行顺序变慢。在跟踪内存分配的程序中,分配确实是瓶颈,这就是为什么Object.
出现在CPU配置文件的顶部。但在实际的程序中,分配/垃圾收集可能是瓶颈,也可能不是瓶颈
您通常希望一次只生成一个概要文件。首先运行java-agentlib:hprof=CPU=samples,depth=20生成CPU配置文件,并分析结果。若CPU配置文件将内存分配/垃圾收集作为瓶颈,那个么,并且只有在那个时,才生成并分析堆配置文件,以查看大部分分配来自何处
另一个答案提出了许多关于分析CPU配置文件的要点。特别是,与查看原始hperf CPU配置文件相比,更容易查看正在使用的内容。此外,为了使包含百分比合理准确,您可能需要增加堆栈采样深度以匹配您的应用程序。谢谢您的回答。我更新了我的问题以反映反馈。正如我在这里解释的那样,我不想在短期内改变算法(我最终会着手),但我想知道是否有办法加快分配。我不确定“数据结构表”到底是什么意思,但下面是它的工作原理。它是一个packrat PEG解析器——这意味着使用PEG形式而不是更传统的CFG形式的递归下降解析器,具有记忆功能(您所指的表?)。在某些情况下,为了使运行时可接受,肯定需要进行内存化。语法由类似于图的数据结构表示。这是必要的,因为作为一个语法宏系统,语法可以在解析时更改。但我非常清楚新对象在何处以及如何实例化。我不确定如何摆脱它们——数据是需要的,必须存储在某个地方。也许我可以自己管理阵列(但这基本上是对象池)。或者我可以简单地将数据保存在堆栈上,但我担心堆栈溢出。@Norswap:只有在频繁删除和重新分配对象时,池才有意义。如果语法可以动态更改,那么预编译它可能会更困难,这正是我所建议的。在堆栈溢出真正发生之前,我也不会担心它,但您最了解您的应用程序。我经常删除和重新分配对象。基本上,解析器为其处理的每个“解析表达式”记录一些信息,并将其存储到对象中。在处理表达式的子级时,必须保留该对象。子对象完成解析后,其信息将与父对象的信息合并
java -agentlib:hprof=heap=sites,cpu=samples,depth=20 MyProg