Java .class文件的最大大小是多少?

2022-09-01 14:03:55

文件是一种记录良好的格式,它定义了部分和大小,因此也定义了最大大小。.class

例如,文件包含幻数(4个字节),一个版本(4个字节),常量池(可变大小)等。但可以在多个级别上定义大小:可以有 65535 个方法,每个方法限制为 65535 个字节。.class

其他限制是什么?而且,如果您要制作最大的.class文件,它将有多大?

如果需要,请将答案限制为 Java。这意味着如果 Scala 或 Clojure(或...)更改了一些限制,请忽略这些值。


答案 1

JVM 规范没有对类文件施加限制,并且由于类文件是可扩展的容器,支持任意自定义属性,因此您甚至可以根据需要将其最大化。

每个属性都有一个类型的大小字段,因此,可以指定最多 () 的数量。由于在实践中,JRE API(方法、工具 API 和 )都一致地使用或来描述类文件,因此不可能创建具有字节 () 以上的类文件的运行时类。u42³²-14GiBClassLoaderUnsafebyte[]ByteBuffer2³¹-12GiB

换句话说,即使是单个自定义属性的大小也可能超过实际可装入类的大小。但是一个类可以有 65535 个属性,再加上 65535 个字段,每个字段都有自己的 65535 个属性,再加上 65535 个方法,每个方法最多也有 65535 个属性。

如果您进行数学计算,您将得出这样的结论:仍然格式良好的类文件的理论最大值可能超过任何实际存储空间(超过2⁶⁵字节)。


答案 2

使用嵌套的最终块制作巨大的StackMapTable非常容易,因为javac不明智地为每个嵌套级别生成单独的变量。这允许从非常简单的方法产生几兆字节,如下所示:

class A {{
  int a;
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  a=0;
  }}}}}}}}}}}}
}}

无法添加更多嵌套级别,因为单个方法的代码大小将超过代码大小。您还可以使用实例初始值设定项复制到每个构造函数的事实来复制此内容:

class A {{
  int a;
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  try {a=0;} finally {
  a=0;
  }}}}}}}}}}}}
}
A() { }
A(int a) { }
A(char a) { }
A(double a) { }
A(float a) { }
A(long a) { }
A(short a) { }
A(boolean a) { }
A(String a) { }
A(Integer a) { }
A(Float a) { }
A(Short a) { }
A(Long a) { }
A(Double a) { }
A(Boolean a) { }
A(Character a) { }

}

这个简单的java文件在使用Java 8 javac编译时会产生105,236,439字节.class文件。您还可以添加更多构造函数,尽管存在javac失败的风险(用于克服这一点)。OutOfMemoryErrorjavac -J-Xmx4G


推荐