我想知道为什么我们通过编译显示“ Hello,World!”的.c文件得到.o文件。是否大于Java .class文件,该文件也显示“
Hello,World!”?
Java使用字节码来独立于平台并进行“预编译”,但是字节码由解释器使用并且被提供为足够紧凑,因此您在已编译的C程序中看到的机器代码并不相同。只需看一下Java编译的完整过程即可:
Java program
-> Bytecode
-> High-level Intermediate Representation (HIR)
-> Middle-level Intermediate Representation (MIR)
-> Low-level Intermediate Representation (LIR)
-> Register allocation
-> EMIT (Machine Code)
这是Java程序到机器代码转换的链。如您所见,字节码与机器代码相距甚远。我在Internet上找不到能在实际程序上向您展示这条路的东西(一个示例),我发现的只是此演示文稿,在这里您可以看到每个步骤如何更改代码演示文稿。我希望它能回答您如何以及为何编译的c程序和Java字节码不同。
更新:
“字节码”之后的所有步骤都由JVM在运行时完成,这取决于其编译该代码的决定(这是另一回事了……JVM在字节码解释和其编译成与本地平台相关的代码之间取得平衡)
最终找到了一个很好的例子,摘自Java
HotSpot™客户端编译器的线性扫描寄存器分配
(很好地理解了JVM内部的情况)。想象一下,我们有Java程序:
public static void fibonacci() {
int lo = 0;
int hi = 1;
while (hi < 10000) {
hi = hi + lo;
lo = hi - lo;
print(lo);
}
}
那么它的字节码是:
0: iconst_0
1: istore_0 // lo = 0
2: iconst_1
3: istore_1 // hi = 1
4: iload_1
5: sipush 10000
8: if_icmpge 26 // while (hi < 10000)
11: iload_1
12: iload_0
13: iadd
14: istore_1 // hi = hi + lo
15: iload_1
16: iload_0
17: isub
18: istore_0 // lo = hi - lo
19: iload_0
20: invokestatic #12 // print(lo)
23: goto 4 // end of while-loop
26: return
每个命令占用1个字节(JVM支持256个命令,但实际上少于该数目)+参数。总共需要27个字节。我省略了所有阶段,现在可以执行机器代码了:
00000000: mov dword ptr [esp-3000h], eax
00000007: push ebp
00000008: mov ebp, esp
0000000a: sub esp, 18h
0000000d: mov esi, 1h
00000012: mov edi, 0h
00000017: nop
00000018: cmp esi, 2710h
0000001e: jge 00000049
00000024: add esi, edi
00000026: mov ebx, esi
00000028: sub ebx, edi
0000002a: mov dword ptr [esp], ebx
0000002d: mov dword ptr [ebp-8h], ebx
00000030: mov dword ptr [ebp-4h], esi
00000033: call 00a50d40
00000038: mov esi, dword ptr [ebp-4h]
0000003b: mov edi, dword ptr [ebp-8h]
0000003e: test dword ptr [370000h], eax
00000044: jmp 00000018
00000049: mov esp, ebp
0000004b: pop ebp
0000004c: test dword ptr [370000h], eax
00000052: ret
结果需要83个字节(十六进制52个+ 1字节)。
PS。我没有考虑链接(其他人提到过),也没有考虑编译的c和字节码文件头(可能也有所不同;我不知道c怎么回事,但是在字节码文件中,所有字符串都移到了特殊的标头池,并且在程序中在标头等处使用其“位置”。)
UPDATE2: 也许值得一提的是,尽管基于x86和大多数其他平台的机器代码可以与寄存器一起使用,但是java与堆栈(istore /
iload命令)一起使用。如您所见,机器代码充满了寄存器,与更简单的基于堆栈的字节码相比,它为编译的程序提供了更大的空间。
问题内容: 如何批量反编译许多类文件? 问题答案: JD-Gui使您的生活变得轻松,它还具有一个eclipse插件 编辑:更新了该工具的最新网址
问题内容: 我可以使用什么程序反编译类文件?我实际上会得到Java代码,还是仅仅是JVM汇编代码? 关于此站点上的Java性能问题,我经常看到“反编译” Java类文件以了解编译器如何优化某些东西的人们的回答。 问题答案: 有一些反编译器…快速搜索结果: Procyon: open-source (Apache 2) and actively developed Krakatau: open-so
我写了下面提到的一个简单的java程序。不幸的是,编译错误发生了。 在编译过程中,在命令提示符下会显示以下内容: c:\Java 它对我的任何程序都不起作用,即使是这个简单的程序也不行!这是为什么? 编辑: 现在我有: 而且它不起作用。为什么不起作用? 它说的和以前一样。 你对Java所说的。lang.String[]有效,但为什么不能呢?为什么我以前不需要穿上这些?
问题内容: 我保存了Java源文件,将其编码类型指定为UTF-8(使用记事本,默认情况下,记事本的编码类型为ANSI),然后尝试使用以下命令对其进行编译: 但它给出了错误信息” 还有什么其他方法可以编译吗? 来源如下: 问题答案: 您的文件 被 读为UTF-8,否则有值“65279”字符就绝不可能出现。期待你的源代码是在平台默认的编码,根据该文件: 如果未指定 -encoding ,则使用平台默认
问题内容: 您好,我有3个Java文件 我设法使用生成了A和B的.class文件 但是当我对c.java执行相同操作时,出现错误错误:找不到符号b和c 关于如何解决此问题的任何建议? 所有的Java文件都在同一个文件夹中 问题答案: 尝试编译class时,必须具有类并且在类路径中。这使编译器可以验证它们是否存在,找出它们具有哪些方法等。 对包名称和类路径非常敏感。最简单的方法是像这样同时编译这三个
我已经编译了我的。proto文件使用protobuf编译器并收到了一组Java文件。我收到了一份原始文件。java文件和。中每个项目的java文件。proto文件,包括消息类型和每个RPC调用,例如publicKeyRequest。java和Quote。java作为RPC和请求参数类型。 这是所有需要的文件吗,因为我似乎仍然无法从服务器获得任何简单的响应? 我想为PublicKeyRequest