java - 在Object。<init>(hprof)中花费的时间

我正在分析我的一个应用程序——它是一个建立在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>上的时间是什么原因?它真的与内存分配有关吗?使用对象池或其他技巧来减少内存分配,我能从中受益吗?
编辑:
针对迈克·邓拉维的回答,这里是对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>调用是从ArrayListParseDataParseErrors的初始化开始的)
现在,这并没有真正改变我对这个问题的看法,也没有改变我的问题。我可以改变算法,使其实例化更少的对象;但目前,我正在寻找一个正交的解决方案。那么:对象池可以帮助我吗?

最佳答案

1)“self”时间几乎总是无用的,因为真正的问题是在您的代码中调用那些低级方法-get inclusive time(self+callees)。
2)“accum”栏甚至更无用,因为它所做的只是将“self”时间相加。
其他的专栏也没告诉你什么有用的。
hprof获取堆栈跟踪。
你需要的是让它们尽可能深。
你不需要大量的数据(与流行的统计错误信息相反),10个可能就足够了。
不过,你确实需要看看并理解它们。
Here's some general info about profiling.
编辑以响应显示jperfanal输出的编辑:
a)看起来堆栈深度只有4。你需要看到尽可能深的堆栈深度。
我不在乎它们呈现输出的方式。
我主要是看看堆栈样本本身。
时间不是最重要的。重要的是发生了什么以及为什么。
b)堆栈样本实际上包含行级信息。因此,它们将指向您的例程中的精确行,如parser.ParseData.<init>parser.Matcher.parseparrser.ParseErrors.<init>,其中发生问题的调用。
这将准确地告诉你哪些分配一直在花费,然后你可以决定是否有更好的方法来做这些。
我得到的印象是解析器从数据结构表中运行。
我知道你不想重新设计它,但如果你重新设计它,你会得到更好的性能。
基本上,如果您可以将其表示为递归下降语法分析器,并且如果语言不经常更改,那么您可以直接用代码编写语法分析器(不使用表),而且它的速度会快10-100倍。

本文翻译自 https://stackoverflow.com/questions/18245217/

网站遵循 CC BY-SA 4.0 协议,转载或引用请注明出处。

标签 java memory profiling hprof


相关文章:

c# - 是否有必要取消订阅活动?

python - 通过许多属性和字典查找来优化Python代码

java - 是否需要检查JPA模型类的equals方法中的所有字段?

java - 当我tar文件时,其抛出异常为“太长(> 100字节)TarArchiveOutputStream”

java - 在eclipse中找不到runit作为junit测试

c - 查看释放的内存会导致访问冲突吗?

java - 为什么从串行GC切换到G1会增加RSS

android - 如何使用Xamarin 6.0.1 Community Edition开始对Android设备进行性能分析

node.js - 分析节点应用程序:花费在节点本身上的大部分时间

java - 依赖的Spring项目中的Java配置bean未初始化