我希望显示从一段完全相同的代码生成的汇编程序代码。例如:
int a = 100;
int b = 50;
int c = a + b;
我正在为我的团队在工作中做一个小型的入门课程,人们已经开始对性能等问题,并希望能够向他们展示这个例子。
答案 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]
为了能够看到优化的本机代码,请执行以下操作:
如果从调试器开始,输出将不相同。它将不那么优化..
答案 2 :(得分:1)
Java和C#(通常)不编译成机器代码,它们编译成字节代码。在C#的情况下,这个字节代码由CLR执行,在Java的情况下它是JVM。如果要查看java字节码,可以使用javap
。
你甚至不能保证这个字节码会被执行 - Java的Hotspot编译器会在运行时不断动态地拉动字节码。
作为一般规则,C#和Java处于对绝大多数应用程序而言性能足够好的级别。微优化不再值得担心,选择一种基于哪一种做更多微优化的语言有点不起作用(特别是在Java和C#之间)。