代码过长,编译失败

原文:代码过长,编译失败 — 养恐龙

今天当发版工具人时遇到编译报错「代码过长(code too large)」,把这段说明发到工作群里,瞬间听到周围一片爽朗的笑声……

挺让我惊讶,原来 Java 里的方法大小是有限制的——编译后的字节码大小不能超过 64kb。

JVM 规范 Chapter 4. The class File Formatclass 结构的 method_info (方法信息)里定义了一个 u1 类型1的数组来保存该 Java 方法编译后的数据,这个数组的大小由一个 u2 类型2的变量确定。

1 个 u2 类型的值占 2 byte, 2 byte 就是 16 bit(位),16 bit 所能表示的最大值是 2 的 16 次方——65536。因此一个 u2 类型的变量的最大值就是 65536,所以这个数组也就最多只能保存 65536 byte,即 64kb 的数据。(1 kb = 1024 byte)

这个错误虽然可以在编译期间暴露,但 JVM 并不能保证它加载的 class 文件都是满足要求的,因此在加载 class 文件的验证阶段,还会对该数组的长度进行检查。


除了普通方法外,构造方法、初始化代码块也受到此限制。

初始化代码块为什么也受到此限制呢?我猜测初始化代码块在 JVM 层面还是当作方法来使用的。

同时,如果一个 Java 类里有多个初始化代码块,虽然每个代码块里的代码没有超出此限制,但当它们之和超过该限制时,也会编译报错「代码过长」。我猜测多个初始化代码块在 JVM 层面会被优化成一个方法来使用。

代码块保存在 JVM 的哪块区域?

比如:

public class DayOne{
  {
    System.out.println("哈哈哈哈哈");
    // repeat 4000 times
    System.out.println("哈哈哈哈哈");
  }
  {
    System.out.println("哈哈哈哈哈");
    // repeat 4000 times
    System.out.println("哈哈哈哈哈");
  }
  {
    System.out.println("哈哈哈哈哈");
    // repeat 4000 times
    System.out.println("哈哈哈哈哈");
  }
}

更有趣的是,Java 中数组的大小理论上与 int 的取值范围相关,但实际上可能在初始化数组时,还未达到最大容量便报错「代码过长」:

{
	String[] arr = new String[]{
    "哈哈哈含安安安安哈哈哈含安安安安哈哈哈含安安安安哈哈哈含安安安安",
    //…… repeat 10000 times
    "哈哈哈含安安安安哈哈哈含安安安安哈哈哈含安安安安哈哈哈含安安安安"
	}
}

类似的,JVM 规范 还介绍了「类或接口可以声明的字段数量限制在 65535」「方法参数的数量限制为 255」等情况。:)


  1. 1 byte (字节)的无符号数 ↩︎

  2. 2 byte 的无符号数 ↩︎

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个在 Java 中实现长连接的简单示例代码: ``` import java.io.*; import java.net.*; public class LongConnectionClient { private static final String SERVER_HOST = "localhost"; private static final int SERVER_PORT = 8080; private static final int CONNECTION_TIMEOUT = 5000; private static final int HEARTBEAT_INTERVAL = 10000; public static void main(String[] args) { try { Socket socket = new Socket(); socket.setSoTimeout(CONNECTION_TIMEOUT); socket.connect(new InetSocketAddress(SERVER_HOST, SERVER_PORT)); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); // 发送心跳消息 new Thread(new Runnable() { public void run() { try { while (true) { Thread.sleep(HEARTBEAT_INTERVAL); writer.write("heartbeat\n"); writer.flush(); } } catch (Exception e) { e.printStackTrace(); } } }).start(); // 接收消息 String line; while ((line = reader.readLine()) != null) { System.out.println(line); } socket.close(); } catch (Exception e) { e.printStackTrace(); } } } ``` 这段代码实现了一个长连接的客户端,通过 Socket 连接服务器,并维护心跳和数据传输。在心跳线程中,每隔一段时间发送一个心跳消息;在消息接收循环中,不断接收服务器发送的消息并输出。需要注意的是,在实际应用中还需要对异常和错误进行处理,并根据具体的业务逻辑实现消息的解析和处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值