我正在分析我的一个应用程序——它是一个建立在 Java 之上的宏系统。我正在使用hprof来分析一些基本示例,以下是花费时间的前 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% 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>
如您所见,大部分时间都花在了Object.<init>
. 这对我来说有点模糊。
我的直觉是,时间是由内存分配占用的。使用 C 语言工作让我强烈地感觉到动态内存分配(即malloc()
)效率低下。然而,在 Java 中,福音似乎是 JVM 可以有效地处理短期对象。因此,从诸如对象池之类的模式中没有任何收获。
我应该补充一点,应用程序中最需要性能的部分是解析器,它确实创建了很多短期对象作为其操作的一部分。
你认为花费的时间Object.<init>
是由于什么?它确实与内存分配有关吗?我可以从使用对象池或其他一些技巧来减少内存分配中受益吗?
编辑:
作为对 Mike Dunlavey 的回答的回应,这里是 JPerfAnal 对 hprof 输出的解释,给出了包容性的时间。
Method Times by Caller (times inclusive): 3076 ticks
1: java.lang.Object.<init>: 71,26% (2192 inclusive / 2191 exclusive)
2: com.sun.demo.jvmti.hprof.Tracker.ObjectInit: 0,03% (1 inclusive / 0 exclusive)
3: java.lang.Thread.currentThread: 0,03% (1 inclusive / 1 exclusive)
1: parser.ParseData.<init>: 34,33% (1056 inclusive / 0 exclusive)
2: parser.ParseErrors.<init>: 13,98% (430 inclusive / 1 exclusive)
3: java.lang.Object.<init>: 7,18% (221 inclusive / 221 exclusive)
3: java.util.ArrayList.<init>: 6,76% (208 inclusive / 208 exclusive)
2: java.lang.Object.<init>: 13,52% (416 inclusive / 416 exclusive)
2: java.util.ArrayList.<init>: 6,83% (210 inclusive / 0 exclusive)
3: java.util.ArrayList.<init>: 6,83% (210 inclusive / 210 exclusive)
1: parser.Matcher.parse: 34,33% (1056 inclusive / 0 exclusive)
2: parser.ParseData.<init>: 34,33% (1056 inclusive / 0 exclusive)
3: parser.ParseErrors.<init>: 13,98% (430 inclusive / 1 exclusive)
4: java.lang.Object.<init>: 7,18% (221 inclusive / 221 exclusive)
4: java.util.ArrayList.<init>: 6,76% (208 inclusive / 208 exclusive)
3: java.lang.Object.<init>: 13,52% (416 inclusive / 416 exclusive)
3: java.util.ArrayList.<init>: 6,83% (210 inclusive / 0 exclusive)
4: java.util.ArrayList.<init>: 6,83% (210 inclusive / 210 exclusive)
1: java.util.ArrayList.<init>: 28,38% (873 inclusive / 419 exclusive)
2: java.util.AbstractList.<init>: 14,76% (454 inclusive / 0 exclusive)
3: java.util.AbstractCollection.<init>: 14,76% (454 inclusive / 0 exclusive)
4: java.lang.Object.<init>: 14,76% (454 inclusive / 454 exclusive)
(JPerfAnal 还生成一个倒置树,其中子代是父代的调用者。为简洁起见,我没有复制它,但可以说大约 40% 的Object.<init>
调用来自 和 的初始化。ArrayList
)ParseData
ParseErrors
现在,这并没有真正改变我对这个问题或我的问题的看法。我可以更改算法,使其实例化更少的对象;但目前,我正在寻找一个正交解决方案。那么:对象池可以帮助我吗?