Gra*_*ity 5 java performance memory-management
我在分析 Java 应用程序时发现对象分配的速度比我预期的要慢得多。我运行了一个简单的基准测试来尝试建立小对象分配的整体速度,我发现在我的机器上分配一个小对象(3 个浮点数的向量)似乎需要大约 200 纳秒。我在(双核)2.0 GHz 处理器上运行,所以这大约是 400 个 CPU 周期。我想问一下之前对 Java 应用程序进行过概要分析的人,这种速度是否可以预期。这对我来说似乎有点残忍和不寻常。毕竟,我认为像 Java 这样可以压缩堆并重定位对象的语言将具有如下所示的对象分配:
int obj_addr = heap_ptr;
heap_ptr += some_constant_size_of_object
return obj_addr;
Run Code Online (Sandbox Code Playgroud)
....这是几行组装。至于垃圾收集,我不会分配或丢弃足够的对象来发挥作用。当我通过重用对象来优化我的代码时,我获得了大约 15 纳秒/我需要处理的对象的性能,而不是我需要处理的每个对象 200 ns,因此重用对象极大地提高了性能。我真的不想重用对象,因为这使得符号有点麻烦(许多方法需要接受一个receptacle参数而不是返回一个值)。
所以问题是:对象分配花费这么长时间是否正常?或者我的机器上可能有什么问题,一旦修复,可能会让我在这方面有更好的表现?其他人的小对象分配通常需要多长时间,是否有典型值?我正在使用客户端机器,目前没有使用任何编译标志。如果您的机器运行速度更快,那么您机器的 JVM 版本和操作系统是什么?
我意识到就性能而言,个人里程可能会有很大差异,但我只是想问问我上面提到的数字是否正确。
当对象较小时,创建对象的速度非常快,并且没有 GC 成本。
final int batch = 1000 * 1000;
Double[] doubles = new Double[batch];
long start = System.nanoTime();
for (int j = 0; j < batch; j++)
doubles[j] = (double) j;
long time = System.nanoTime() - start;
System.out.printf("Average object allocation took %.1f ns.%n", (double) time/batch);
Run Code Online (Sandbox Code Playgroud)
打印与-verbosegc
Average object allocation took 13.0 ns.
Run Code Online (Sandbox Code Playgroud)
注意:没有发生 GC。然而,增加大小,程序需要等待在 GC 中复制内存。
final int batch = 10 *1000 * 1000;
Run Code Online (Sandbox Code Playgroud)
印刷
[GC 96704K->94774K(370496K), 0.0862160 secs]
[GC 191478K->187990K(467200K), 0.4135520 secs]
[Full GC 187990K->187974K(618048K), 0.2339020 secs]
Average object allocation took 78.6 ns.
Run Code Online (Sandbox Code Playgroud)
我怀疑你的分配速度相对较慢,因为你正在执行GC。解决这个问题的一种方法是增加应用程序可用的内存。(虽然这可能只是推迟了成本)
如果我再次运行它-verbosegc -XX:NewSize=1g
Average object allocation took 9.1 ns.
Run Code Online (Sandbox Code Playgroud)
我不知道你如何衡量分配时间。它可能内联至少相当于
intptr_t obj_addr = heap_ptr;
heap_ptr += CONSTANT_SIZE;
if (heap_ptr > young_region_limit)
call_the_garbage_collector ();
return obj_addr;
Run Code Online (Sandbox Code Playgroud)
但它比这更复杂,因为你必须填写obj_addr; 然后,可能会发生一些JIT 编译或类加载;很可能,前几个单词被初始化(例如类指针和哈希码,这可能涉及一些随机数生成......),并且调用对象构造函数。它们可能需要同步等。
更重要的是,新分配的对象可能不在最近的一级缓存中,因此可能会发生一些缓存未命中的情况。
因此,虽然我不是 Java 专家,但我对您的措施并不感到惊讶。我确实相信,与尝试重用旧对象相比,分配新对象会使您的代码更干净且更易于维护。
| 归档时间: |
|
| 查看次数: |
3281 次 |
| 最近记录: |