【问题标题】:Java memory allocation performance (SunOS vs Windows)Java 内存分配性能(SunOS 与 Windows)
【发布时间】:2010-11-23 17:00:24
【问题描述】:

我有一个非常简单的单元测试,它只分配了很多字符串:

public class AllocationSpeedTest extends TestCase {

    public void testAllocation() throws Exception {

        for (int i = 0; i < 1000; i++) {
            long startTime = System.currentTimeMillis();
            String a = "dummy";
            for (int j = 0; j < 1000; j++) {
                a += "allocation driven";
            }
            System.out.println(i + ": " + (System.currentTimeMillis() - startTime) + "ms " + a.length());
        }

    }

}

在我的 Windows PC(Intel Core Duo,2.2GHz,2GB)上平均打印:

...
71: 47ms 17005
72: 47ms 17005
73: 46ms 17005
74: 47ms 17005
75: 47ms 17005
76: 47ms 17005
77: 47ms 17005
78: 47ms 17005
79: 47ms 17005
80: 62ms 17005
81: 47ms 17005
...

在 SunOS(5.10 Generic_138888-03 sun4v sparc SUNW、SPARC-Enterprise-T5120)上:

...
786: 227ms 17005
787: 294ms 17005
788: 300ms 17005
789: 224ms 17005
790: 260ms 17005
791: 242ms 17005
792: 263ms 17005
793: 287ms 17005
794: 219ms 17005
795: 279ms 17005
796: 278ms 17005
797: 231ms 17005
798: 291ms 17005
799: 246ms 17005
800: 327ms 17005
...

两台机器上的 JDK 版本都是 1.4.2_18。 JVM参数相同,分别是:

–server –Xmx256m –Xms256m

谁能解释一下为什么 SUN 超级服务器比较慢?

(http://www.sun.com/servers/coolthreads/t5120/performance.xml)

【问题讨论】:

  • 看起来第一台电脑比第二台快。
  • 据推测,SunOS 机器上的测试时间大约是 Windows 机器上的 5-6 倍。

标签: java memory solaris allocation sunos


【解决方案1】:

SunOS 硬件较慢,虚拟机也可能稍慢。

【讨论】:

  • 有没有办法让它更快?
  • SUN 说:“采用芯片多线程 (CMT) 技术的 Sun SPARC Enterprise T5120 服务器提供了突破性的性能水平,同时显着节省了功耗和空间,一系列世界纪录基准测试结果证明了这一点。”不是我真的相信营销牛屎,但为什么会慢?
  • @Superfilin:踩踏板更硬? :-)
  • 这可能就是我需要的:)
  • 该芯片至少有 4 个内核,每个内核可支持 8 个线程。也许在这里增加并发性是提高性能的关键?我认为单线程性能不会给人留下深刻印象。
【解决方案2】:

据我了解,基于 UltraSPARC T2 的机器的目标是每瓦性能,而不是原始性能。您可以尝试将分配时间除以功耗,看看您得到什么样的数字。 :)

您运行 1.4.2 而不是 1.6 有什么原因吗?

【讨论】:

  • 您是否有任何官方链接可以证明这一点;)?
  • ...针对“每幻灯片演示文稿”。它们消耗的功率几乎与英特尔处理器一样多。可能会少 10-20 瓦,但不足以弥补性能损失。
  • “确认”我不知道;我见过的大部分是营销软件。 T2 是八核芯片,不是吗?您可以尝试查看多个线程会发生什么。我刚刚在我的桌面(Core 2 Quad,2.4GHz)上做了一个快速测试,只有 250 个字符串,看起来两个线程可以在大约 1.8 倍的时间内分别分配 250 个线程可以分配 250,但是通过 4 个线程它是花费超过 4 倍的时间。我很好奇它是如何在 T2 上扩展的。
  • 我已经提交了一个单独的答案,描述了 SPARC 上的多线程测试。
  • 我们测试的 T2 是 4 核芯片,但在生产中它将是 8 核。
【解决方案3】:

我不认为这是在测量内存分配。首先,a += "allocation driven"; 中正在进行大量的字符复制。但我怀疑真正的瓶颈在于通过网络层从 Sun 服务器上的应用程序获取来自 System.out.println(...) 的输出到您的远程工作站。

作为一个实验,尝试将内部循环计数乘以 10 和 100,看看相对于您的工作站,这是否“加速”了 Sun 服务器。

您可以尝试的另一件事是将内部循环移动到单独的过程中。由于您在一次调用main 中完成了所有工作,因此 JIT 编译器可能永远没有机会编译它。

(像这样的人工“微基准”总是容易受到这些影响。我倾向于不信任它们。)

【讨论】:

  • 打印时间的表达式是在调用 System.out 之前计算的。所以,这不是瓶颈。
  • 嗯......这不一定遵循。无论如何,试试这个实验。如果你是对的,将内部循环计数乘以 N 将乘以 N。
  • 将内部循环乘以 10 不会将数字增加 10,因为每次连接浪费的内存量会越来越大。它基本上分配了一个新的 char[a.length + "allocationdriven".length] 并将旧数组抛出。因此,每次迭代都会浪费 17*i 个字​​符。这至少等于 17/2*(n^2 - n) 浪费的内存量。因此,将内循环 (n) 增加 10 次将使时间增加 100 倍。相信我 System.out 不在游戏中:)。
  • 该测试只是试图模拟繁重的内存分配并查看它的性能。我只是想解释一下为什么它在 Sun 上这么慢。
  • 好的,我误读了基准(已经很晚了)。对我的理论的更好测试是添加一个中间循环,以便您在检测循环中执行 1000 次串联 N 次。
【解决方案4】:

SPARC (1.2Ghz) 上的 CPU 确实较慢,正如 Sun 的一位工程师所回答的那样,对于单线程应用程序,T2 通常比现代 Intel 处理器慢 3 倍。不过,他还表示,在多线程环境中,SPARC 应该更快。

我使用 GroboUtils 库进行了多线程测试,并测试了分配(通过串联)和简单计算( a += j*j )来测试处理器。我得到了以下结果:

1 thread : Intel : Calculations test : 43ms
100 threads : Intel : Calculations test : 225ms

1 thread : Intel : Allocations test : 35ms
100 threads : Intel : Allocations test : 1754ms

1 thread : SPARC : Calculations test : 197ms
100 threads : SPARC : Calculations test : 261ms

1 thread : SPARC : Allocations test : 236ms
100 threads : SPARC : Allocations test : 1517ms

SPARC 在 100 个线程上的表现超过了英特尔,从而展示了它的强大功能。

多线程计算测试如下:

import java.util.ArrayList;
import java.util.List;

import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner;
import net.sourceforge.groboutils.junit.v1.TestRunnable;
import junit.framework.TestCase;

public class TM1_CalculationSpeedTest extends TestCase {

    public void testCalculation() throws Throwable {

        List threads = new ArrayList();
        for (int i = 0; i < 100; i++) {
            threads.add(new Requester());
        }
        MultiThreadedTestRunner mttr = new MultiThreadedTestRunner((TestRunnable[]) threads.toArray(new TestRunnable[threads.size()]));
        mttr.runTestRunnables(2 * 60 * 1000);

    }

    public class Requester extends TestRunnable {

        public void runTest() throws Exception {
            long startTime = System.currentTimeMillis();
            long a = 0;
            for (int j = 0; j < 10000000; j++) {
                a += j * j;
            }
            long endTime = System.currentTimeMillis();
            System.out.println(this + ": " + (endTime - startTime) + "ms " + a);
        }

    }

}

这里是多线程分配测试:

import java.util.ArrayList;
import java.util.List;

import junit.framework.TestCase;
import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner;
import net.sourceforge.groboutils.junit.v1.TestRunnable;

public class TM2_AllocationSpeedTest extends TestCase {

    public void testAllocation() throws Throwable {

        List threads = new ArrayList();
        for (int i = 0; i < 100; i++) {
            threads.add(new Requester());   
        }
        MultiThreadedTestRunner mttr = new MultiThreadedTestRunner((TestRunnable[]) threads.toArray(new TestRunnable[threads.size()]));
        mttr.runTestRunnables(2 * 60 * 1000);

    }

    public class Requester extends TestRunnable {

        public void runTest() throws Exception {
            long startTime = System.currentTimeMillis();
            String a = "dummy";
            for (int j = 0; j < 1000; j++) {
                a += "allocation driven";
            }
            long endTime = System.currentTimeMillis();
            System.out.println(this + ": " + (endTime - startTime) + "ms " + a.length());
        }

    }

}

【讨论】:

  • 最后的输出是错字吗?那应该又是 SPARC 吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-31
  • 2012-08-06
  • 1970-01-01
相关资源
最近更新 更多