Java 7和8中方法的最大大小

83
我知道在Java中,一个方法的大小不能超过64KB。这个限制会导致我们使用JavaCC语法生成的代码出现问题。我们在Java 6上遇到了问题,并通过更改语法来解决了这个问题。Java 7是否已经改变了这个限制或者计划在Java 8中进行改变?
只是为了明确。我自己不需要一个超过64KB的方法。但我编写了一个编译成非常大方法的语法。

4
当我尝试编译一份庞大的Brainf**k代码时,我遇到了相同的问题。 - johnchen902
3
如果没有相反的信息,我认为可以安全地假设在Java 8中仍将执行此限制... 当然,另一个(代价高昂的)选择是更改parboiled的语法引擎,该引擎允许您使用纯Java编写语法。 - fge
4
请查看此文章:http://chrononsystems.com/blog/method-size-limit-in-java。 - Anirudha
7
我个人认为创建如此大的方法是JavaCC中的一个缺陷。它应该能够分散其代码,特别考虑到JVM绝对不是为优化如此庞大的方法而构建的。 - Joachim Sauer
5个回答

60
根据 JVMS7

事实上,end_pc 是一个排他性的历史性错误,在 Java 虚拟机的设计中:如果一个方法的 Java 虚拟机代码恰好长达 65535 字节,并以一个长度为 1 字节的指令结束,那么该指令将无法由异常处理程序保护。编译器编写者可以通过限制生成的 Java 虚拟机代码的最大大小来解决这个问题,对于任何方法、实例初始化方法或静态初始化程序(任何代码数组的大小)都要限制在 65534 字节以内。

但这是关于 Java 7 的。 Java 8 没有最终规范,因此除了开发人员外,没有人能回答这个问题。

更新 (2015-04-06) 根据JVM8的说法,这也适用于Java 8


2
Java 真的有这样一个“漏洞”吗?它还没有被修复吗?这可能是一个很严重的限制,特别是对于 LaurentG 的情况。 - Francesco Belladonna
3
引用的讨论仅关于该方法的长度比可能的长度少一个字节。这并不重要。限制并非由于像那样简单的“错误”引起的:这在字节码的整体设计中,修复它需要重新指定其全部内容。 - Marko Topolnik

11

很好的问题。我们应该去源头查找答案("Java®虚拟机规范")。尽管本节没有明确提到限制(与Java6 VM规范不同),但有点含蓄地说:

在调用方法(§2.6)时创建的帧中的局部变量数组中的局部变量数量由Code属性(§4.7.3)的max_locals项的大小和Java虚拟机指令集的16位局部变量索引限制,最大为65535。

祝好!


7
“最大数量的本地变量”恰好具有相同的数值,但仍然是与OP所问的“方法的最大大小”完全不同的东西。 - Holger

8
它没有改变。在Java 7和Java 8中,方法中的代码限制仍为64 KB。
参考文献:
1. 来自Java 7虚拟机规范(4.9.1 Static Constraints):
针对类文件中Java虚拟机代码的静态约束指定了Java虚拟机指令在代码数组中的布局方式以及各个指令的操作数必须是什么。
代码数组的静态约束如下:
- 代码数组不能为空,因此code_length项目的值不能为0。 - code_length项目的值必须小于65536。
2. 来自Java 8虚拟机规范(4.7.3 The Code Attribute):

code_length项的值给出了此方法中代码数组中的字节数。

code_length的值必须大于零(因为代码数组不能是空的),并且小于65536。


1

Andremoniy已经回答了这个问题的java 7部分,但似乎当时还没有决定关于java 8的问题,所以我来补充一下答案以涵盖这部分:

引用自jvms

end_pc是排除在外的事实,在Java虚拟机的设计中是一个历史性错误:如果方法的Java虚拟机代码恰好长65535字节,并以一个长度为1字节的指令结尾,则该指令不能由异常处理程序保护。编译器编写者可以通过将生成的Java虚拟机代码的最大大小限制为任何方法、实例初始化方法或静态初始化程序(任何代码数组的大小)65534字节来解决此错误。

正如您所看到的,这个历史性问题在这个版本(java 8)中似乎并没有得到解决。


-1

作为一种权宜之计,如果你可以访问解析器的代码,你可以修改它以适应JVM编译器所施加的任何限制... (假设在解析器代码中找到要修改的部分不会耗费太长时间)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接