为啥 FileChannel.map 占用了 Integer.MAX_VALUE 的数据?

Posted

技术标签:

【中文标题】为啥 FileChannel.map 占用了 Integer.MAX_VALUE 的数据?【英文标题】:Why does FileChannel.map take up to Integer.MAX_VALUE of data?为什么 FileChannel.map 占用了 Integer.MAX_VALUE 的数据? 【发布时间】:2011-12-25 23:06:55 【问题描述】:

使用 FileChannel.map 时出现以下异常

Exception in thread "main" java.lang.IllegalArgumentException: Size exceeds Integer.MAX_VALUE
    at sun.nio.ch.FileChannelImpl.map(Unknown Source)
    at niotest.NioTest.readUsingNio(NioTest.java:38)
    at niotest.NioTest.main(NioTest.java:64)

快速查看 OpenJdk 实现表明 FileChannelImpl 中的方法 map(..) 将 long 类型的 size 作为输入。但在正文中,它将它与Integer.MAX_VALUE 进行比较,如果大于则抛出错误。为什么将long 大小作为输入,但将其限制为最大integer 长度?

有人知道这个实现背后的具体原因吗? 还是某种错误?

来源网址 - http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/nio/ch/FileChannelImpl.java

我在 64 位 Windows-2k8 上使用 64 位 JRE 运行此程序

【问题讨论】:

【参考方案1】:

这不是特定于实现的错误。大小是在FileChannel.map 中定义的一样长,但是...

size - 要映射的区域的大小;必须为非负且不大于 Integer.MAX_VALUE

所有兼容的 JVM 实现都将采用这种方式。我怀疑原因是历史(谁需要访问大于 2GB 的文件?;)和试图在 Java 的更高版本中推动事情的结合(允许大于 Integer.MAX 的值比它更容易将数据类型从int更改为long。)

很多人在 Java API 中发现这种基于 int 的思想对于任何文件都非常混乱和短视。但请记住,Java 于 1995 年开始开发!我敢肯定 2GB 在当时似乎是一个相对安全的值。

【讨论】:

真正的原因是 ByteBuffer.capacity 仅限于 int 的范围,NIO 是 1.4 进来的,所以没有像 '95 @bestsss:他们选择了int 而不是long,这在当时是不够的。 long 从第 0 天开始就使用 Java。(在 32 位机器上,使用 64 位数字会昂贵。)和“是”,Java 1.4 于 2002 年 2 月发布,但 NIO 起源于 JSR 51,于 2000 年 1 月正式启动。(2000 年平均销售的 HDD 大小为 10GB?20GB?) JSR 51 的最初起源是在那之前几个聪明的工程师之间的一品脱啤酒。肯定不会迟于 1999 年底。 我对 HDD 的记忆是 80GB,java 一直瞄准 solaris big iron。 File.length() 自 Java 诞生以来一直是 long。选择int 与 CPU 中的内部优化和分支预测有关。例如,for(long i=....) 从未优化或展开...并且您希望 ByteBuffer 上的循环既消除范围检查又展开。 我说的是“平均”,而不是“最大”。 en.wikipedia.org/wiki/File:Hard_drive_capacity_over_time.svg (令人惊讶的是,这些数字看起来如此之小。我从千字节时代开始就一直在购买存储空间......这太棒了。) 我认为我的观点是:int over long 因为时间是有意义的。欢迎您在 1995 年与 1999 年分道扬镳,但这并不夸张。 哦,那时的 Java 也瞄准了“一次编写,随处运行......包括 GUI 的东西”......不仅仅是沉重的 Sun 工具包。【参考方案2】:

ByteBuffer 的容量被限制为 Integer.MAX_VALUE,所以没有办法映射比它更大的东西。

看:MappedByteBuffer map(MapMode mode, long position, long size)position 必须很长,原因很明显。size 不需要很长,但在任何计算中都必须提升它 - 例如位置+大小必须是正多头。操作系统映射确实可以使用long 来承载映射,map 函数 (mmap) 可能需要映射超过 Integer.MAX_VALUE 以保留页面大小,但 ByteBuffer 不能使用它。

总体上int在java的设计中很深,没有size_t类似的C类型,大量使用long而不是int会降低性能。所以最后:如果您需要大于 2GB 的地图,只需使用多个 ByteBuffer。

【讨论】:

以上是关于为啥 FileChannel.map 占用了 Integer.MAX_VALUE 的数据?的主要内容,如果未能解决你的问题,请参考以下文章

JavaNIO的深入研究4内存映射文件I/O

C题:为啥char实际上占用了4个字节的内存?

为啥我的 HSQLDB 表在磁盘上占用了太多空间?

windows服务器为啥我的新版的phpstudy8.0自带的ftp报530 user cannot log in?

为啥 Kernel#require 占用了我的应用程序资源的这么大块?

HTML:为啥元素占用这么多宽度?