使用Files.readAllBytes()读取未知大小文件可能导致堆内存溢出,如何避免?
- 内容介绍
- 相关推荐
本文共计782个文字,预计阅读时间需要4分钟。
`Files.readAllBytes()` 是 Java 中一个危险的快捷方法——它不检查文件大小,只会将整个文件内容一次性加载到内存中。这意味着,如果文件非常大,可能会导致内存溢出。
直接申请超限字节数组,JVM 地址空间都扛不住
该方法返回 byte[],而数组长度必须是 int 类型(最大 2³¹−1 ≈ 2.1GB)。一旦文件超过这个大小,哪怕只有 2.2GB,就会抛出 java.lang.OutOfMemoryError: Required array size too large。这不是堆不够,而是 JVM 根本不允许创建这么大的数组——连尝试分配的机会都不给。
更隐蔽的是:在 64 位 JVM 上,-Xmx32g 看似充足,但 readAllBytes() 仍会先尝试申请一个 ≈ 文件原始字节大小的连续 byte[]。100GB 文件 → 需要 100GB 连续虚拟地址空间,远超多数系统默认限制,直接失败。
隐式触发字符串膨胀,二次放大内存压力
开发者常紧接着写:new String(bytes, StandardCharsets.UTF_8)。
本文共计782个文字,预计阅读时间需要4分钟。
`Files.readAllBytes()` 是 Java 中一个危险的快捷方法——它不检查文件大小,只会将整个文件内容一次性加载到内存中。这意味着,如果文件非常大,可能会导致内存溢出。
直接申请超限字节数组,JVM 地址空间都扛不住
该方法返回 byte[],而数组长度必须是 int 类型(最大 2³¹−1 ≈ 2.1GB)。一旦文件超过这个大小,哪怕只有 2.2GB,就会抛出 java.lang.OutOfMemoryError: Required array size too large。这不是堆不够,而是 JVM 根本不允许创建这么大的数组——连尝试分配的机会都不给。
更隐蔽的是:在 64 位 JVM 上,-Xmx32g 看似充足,但 readAllBytes() 仍会先尝试申请一个 ≈ 文件原始字节大小的连续 byte[]。100GB 文件 → 需要 100GB 连续虚拟地址空间,远超多数系统默认限制,直接失败。
隐式触发字符串膨胀,二次放大内存压力
开发者常紧接着写:new String(bytes, StandardCharsets.UTF_8)。

