Java与C#机器代码做同样的事情

时间:2011-02-22 10:38:14

标签: c# java assembly

我希望显示从一段完全相同的代码生成的汇编程序代码。例如:

int a = 100;
int b = 50;
int c = a + b;

我正在为我的团队在工作中做一个小型的入门课程,人们已经开始对性能等问题,并希望能够向他们展示这个例子。

3 个答案:

答案 0 :(得分:9)

嗯,Java编译器和(普通)C#编译器都不会从源代码生成“本机”汇编代码。它们将分别生成Java字节码或IL代码。然后,根据正在使用的VM,该代码可能最终被解释或JIT编译 - 并且可能多次编译JIT(例如,在HotSpot上)。

例如,这是源代码的Java字节码,在我的工作站上使用javac编译(对于这样一个简单的示例,它不太可能有很大不同,但显然对于更复杂的代码,用于生成字节码/ IL的选项:

// Java bytecode
0:  bipush  100
2:  istore_1
3:  bipush  50
5:  istore_2
6:  iload_1
7:  iload_2
8:  iadd
9:  istore_3

这里是来自C#编译器的IL:

// IL
IL_0001:  ldc.i4.s   100
IL_0003:  stloc.0
IL_0004:  ldc.i4.s   50
IL_0006:  stloc.1
IL_0007:  ldloc.0
IL_0008:  ldloc.1
IL_0009:  add
IL_000a:  stloc.2

如果您想知道在任何一个时间点为该代码运行的本机代码,通常需要某种调试器,例如:用于.NET的cordbg。即使这样,您也需要确保打开相应的JIT编译器优化,就像调试时使用优化一样,因为它会使调试行为变得更加困难。然后请记住,使用像HotSpot这样的东西,下次该方法被击中时你很可能不会运行相同的代码......

通常不应在汇编代码级别考虑性能,因为忽略了太多的上下文 - 缓存中的内容,此代码运行的频率,一个分支或另一个分支的频率。通常重要的是整个应用程序在现实生活中使用时的行为(或者某些子系统或其他)。

答案 1 :(得分:3)

关于C#: 如果你在releasemode中运行并且没有附加调试器,那么整个代码块将被删除,因为它没有被使用。

如果使用“c”变量,则值150将被编译到该代码中,因此不会进行添加操作。

   13:             Console.WriteLine(c);
00000003 E8 58 70 55 63       call        63557060 
00000008 8B C8                mov         ecx,eax 
0000000a BA 96 00 00 00       mov         edx,96h             <- 150 
0000000f 8B 01                mov         eax,dword ptr [ecx] 
00000011 8B 40 38             mov         eax,dword ptr [eax+38h] 
00000014 FF 50 14             call        dword ptr [eax+14h] 

为了能够看到优化的本机代码,请执行以下操作:

  • 在代码末尾添加Console.ReadLine()。
  • 编译为发布
  • 在没有调试器的情况下启动
  • 应用等待readline后,调试 - &gt;附加到流程
  • 点击
  • 将堆栈跟踪导航到要查看的功能。

如果从调试器开始,输出将不相同。它将不那么优化..

答案 2 :(得分:1)

Java和C#(通常)不编译成机器代码,它们编译成字节代码。在C#的情况下,这个字节代码由CLR执行,在Java的情况下它是JVM。如果要查看java字节码,可以使用javap

你甚至不能保证这个字节码会被执行 - Java的Hotspot编译器会在运行时不断动态地拉动字节码。

作为一般规则,C#和Java处于对绝大多数应用程序而言性能足够好的级别。微优化不再值得担心,选择一种基于哪一种做更多微优化的语言有点不起作用(特别是在Java和C#之间)。