为什么java文件编译不_为什么编译的Java类文件比C的编译文件小?

小编典典

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命令)一起使用。如您所见,机器代码充满了寄存器,与更简单的基于堆栈的字节码相比,它为编译的程序提供了更大的空间。

2020-11-01

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值