java mono 性能比较_.NET、Mono与Java、C++性能测试大PK(2)

.NET和Mono C#性能测试代码

bc35022f5ffbfca200e6794321f71a96.png

在调用的.NET代码中计算启动时间和C++有点不同,它使用了DateTime中的FromFileTimeUtc辅助方法。

privateconstlongTicksPerMiliSecond = TimeSpan.TicksPerSecond / 1000;

staticintMain(string[] args)

{

DateTime mainEntryTime = DateTime.UtcNow;//100 nanoseconds units since 1601/1/1

intresult = 0;

if(args.Length > 0)

{

DateTime launchTime = System.DateTime.FromFileTimeUtc(long.Parse(args[0]));

longdiff = (mainEntryTime.Ticks - launchTime.Ticks) / TicksPerMiliSecond;

result = (int)diff;

}

else

{

System.GC.Collect(2, GCCollectionMode.Forced);

System.GC.WaitForPendingFinalizers();

System.Threading.Thread.Sleep(5000);

}

returnresult;

}

使用Mono

要使用Mono必须先从这里下载并安装好Mono,然后修改环境变量PATH,增加C:\PROGRA~1\MONO-2~1.4\bin\,注意你使用的Mono版本号可能会有些不同,另外,安装时可以不选中GTK#和XSP组件,因为本次测试用不着它们,为了简化编译操作,我特意写了一个buildMono.bat批处理文件,已包含在本文提供的下载包中。

使用更多.NET版本

我还包括了1.1,2.0,3.5和4.0版本的C# Visual Studio项目,如果你只需运行二进制文件,需要下载和安装对应的运行时,生成(Build)时需要Visual Studio 2003和Visual Studio 2010,或如果你喜欢使用命令生成,还需要特定的SDK。为了强制加载目标运行时版本,我为所有.NET执行文件创建了配置文件,内容如下,不同的地方就是版本号:

Java性能测试代码

f310cd9d4f6014b95299f7871c80fcfb.png

首先要从这里下载并安装Java SDK,同样也需要向PATH环境变量添加Java路径,在开始生成前,还需要设置javac.exe的编译路径,如:

setpath=C:\Program Files\Java\jdk1.6.0_16\bin;%path%

在本文提供的压缩包中,我提供了一个buildJava.bat批处理文件来帮助你完成生成操作,Java性能测试代码如下:

publicstaticvoidmain(String[] args)

{

longmainEntryTime = System.currentTimeMillis();//miliseconds since since 1970/1/1

intresult =0;

if(args.length >0)

{

//FileTimeUtc adjusted for java epoch

longfileTimeUtc = Long.parseLong(args[0]);//100 nanoseconds units since 1601/1/1

longlaunchTime = fileTimeUtc - 116444736000000000L;//100 nanoseconds units since 1970/1/1

launchTime /=10000;//miliseconds since since 1970/1/1

result = (int)(mainEntryTime - launchTime);

}

else

{

try

{

System.gc();

System.runFinalization();

Thread.sleep(5000);

}

catch(Exception e)

{

e.printStackTrace();

}

}

java.lang.System.exit(result);

}

由于Java缺乏测量持续时间的解决方案,我不得不使用毫秒,其它框架可以提供更细粒度的时间单位,但毫秒在这次的测试中已经够用了。

获取内存使用情况和处理器时间

Windows进程有许多层面都会使用内存,我将仅限于测量专用字节,最小工作集和峰值工作集。如果你想知道没有参数时,调用的进程为什么会等待5秒,现在你应该有答案了。在等待2秒后,调用者将使用下面的代码测量内存使用情况:

BOOL PrintMemoryInfo(constPROCESS_INFORMATION& pi)

{

//wait 2 seconds while the process is sleeping for 5 seconds

if(WAIT_TIMEOUT != WaitForSingleObject( pi.hProcess,2000))

returnFALSE;

if(!EmptyWorkingSet(pi.hProcess))

printf("EmptyWorkingSet failed for %x\n", pi.dwProcessId );

BOOL bres = TRUE;

PROCESS_MEMORY_COUNTERS_EX pmc;

if( GetProcessMemoryInfo( pi.hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)) )

{

printf("PrivateUsage: %lu KB,", pmc.PrivateUsage/1024);

printf(" Minimum WorkingSet: %lu KB,", pmc.WorkingSetSize/1024);

printf(" PeakWorkingSet: %lu KB\n", pmc.PeakWorkingSetSize/1024);

}

else

{

printf("GetProcessMemoryInfo failed for %p", pi.hProcess );

bres = FALSE;

}

returnbres;

}

最小工作集是调用的进程占用的内存由EmptyWorkingSet API收缩后,我计算出的一个值。

测试结果

这些测试产生的结果很多,我只挑选了与本文主题相关的一些数据,并将热启动的测试结果也一并展示出来了,如图1所示。如果你以调试模式执行测试,产生的结果会更多,对于热启动,我执行了9次测试,而冷启动只有一次,我只采用了中间值(即去掉了最高分和最低分),处理器内核和用户时间被归结到一块儿,总称为CPU时间,下表的结果是来自一台奔四3.0GHz,2GB内存的Windows XP机器的测试结果。

运行时

冷启动时间(ms)

冷启动CPU时间(ms)

热启动时间(ms)

热启动CPU时间(ms)

专用字节(KB)

最小工作集(KB)

峰值工作集(KB)

.Net 1.1

1844

156

93

93

3244

104

4712

.Net 2.0

1609

93

78

93

6648

104

5008

.Net 3.5

1766

125

93

77

6640

104

4976

.Net 4.0

1595

77

46

77

7112

104

4832

Java 1.6

1407

108

94

92

39084

120

11976

Mono 2.6.4

1484

156

93

92

4288

100

5668

CPP code

140

30

15

15

244

40

808

注意其中.NET 2.0和.NET 4.0的热启动时间比热启动CPU时间要低,你可能认为这违背了基本的物理定律,但需要注意这里的CPU时间指的是进程的整个生命周期,而启动时间仅仅指进入到main函数时的时间,通过这我们知道可以通过一些优化提高这些框架的启动速度,正如你前面看到的,C++由于没有框架,因此优势很明显,调用者进程通过预加载一些通用dll使启动更快。

我没有所有运行时的历史数据,但从.NET各版本的表现来看,越新的版本会通过消耗更多的内存来提速,如下图所示。

27b4bd985786996ca24353a1ce8ce33b.png

图 2 .NET框架不同版本程序热启动时性能表现(值越小越好)

为托管运行时使用原生镜像

除了C++原生代码外,所有运行时都使用了中间代码,下一步如果可能应该尝试生成原生镜像,并再次评估它们的性能,Java没有一个易于使用的工具来完成这项任务,GCJ只能完成一半的任务,而且它还不是官方运行时的一部分,因此我会忽略它。Mono有一个类似的功能叫做Ahead of Time(AOT),遗憾的是,AOT尚不能在Windows上工作。.NET从一开始就支持原生代码生成,ngen.exe就是运行时的一部分。

为了方便你,我在本文提供的压缩包中提供了一个make_nativeimages.bat批处理文件,用它快速生成测试用程序集的原生镜像。下表展示了.NET框架各版本原生镜像的测试结果。

运行时

冷启动时间(ms)

冷启动CPU时间(ms)

热启动时间(ms)

热启动CPU时间(ms)

专用字节(KB)

最小工作集(KB)

峰值工作集(KB)

.Net 1.1

2110

140

109

109

3164

108

4364

.Net 2.0

1750

109

78

77

6592

108

4796

.Net 3.5

1859

140

78

77

6588

108

4800

.Net 4.0

1688

108

62

61

7044

104

4184

我们似乎又再次遇到违背物理定律的事情了,上表显示原生编译的程序集冷启动时间更高,不必大惊小怪,因为加载原生镜像也需要大量的I/O操作,从测试结果来看,它比加载框架所用的时间更多。

运行测试

你可以将测试的可执行文件作为一个参数传递给BenchMarkStartup.exe运行一个特殊的测试,对于Java,包名必须匹配目录结构,因此JavaPerf.StartupTest需要一个..\JavaPerf文件夹。

我在本文提供的压缩包中提供了一个runall.bat批处理文件,但它无法捕捉现实的冷启动时间。

如果你想执行真实的测试,你可以手动重启,或在夜间每隔20-30分钟调度执行release文件夹的benchmark.bat批处理文件,然后从文本日志文件获得结果。重启机器后,它将会运行所有运行时的真实测试。

最新的计算机通常会控制CPU频率以节约能源,但这可能会影响到测试结果,因此在运行测试之前,除了前面我已经提到的事情外,你还必须将电源使用方案设置为“高性能”,以便获得一致的结果。

小结

如果你有条件下载文后提供的压缩包按照本文介绍的内容亲自做一下对比测试,相信你对托管运行时和原生代码有更深刻的认识,如果你正在犹豫不决地选择开发平台,本文也可以帮助你确定清晰的方向,另外,你还可以参照本文创建其它运行时或UI测试。

本文使用到的测试源代码和批处理文件从这里下载,我还对Java和Mono专门制作了一个压缩包,从这里下载。

原文名:Benchmark start-up and system performance for .Net, Mono, Java and C++ native code

【编辑推荐】

【责任编辑:彭凡 TEL:(010)68476606】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值