【问题标题】:Java MappedByteBuffer.get() surprisingly slowJava MappedByteBuffer.get() 出奇的慢
【发布时间】:2012-11-20 12:42:34
【问题描述】:

我试图了解我从 MappedByteBuffer 类的 get() 方法获得的性能是否正常。我的代码如下:

private byte[] testBuffer = new byte[4194304];
private File sdcardDir, filepath;
private FileInputStream inputStream; 
private FileChannel fileChannel;
private MappedByteBuffer mappedByteBuffer;

// Obtain the root folder of the external storage
sdcardDir = Environment.getExternalStorageDirectory();

// Create the reference to the file to be read
filepath = new File(sdcardDir, "largetest.avi");
inputStream = new FileInputStream(filepath);
fileChannel = inputStream.getChannel();

mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, (4194304));

Log.d("GFXUnpack", "Starting to read");
mappedByteBuffer.position(0);
mappedByteBuffer.get(testBuffer, 0, (4194304));
Log.d("GFXUnpack", "Ended to read");
mappedByteBuffer.rewind();

由于我是初学者,并且我需要从 SD 卡读取数据的最快方法,因此我查找了文档,发现文件映射在许多情况下被认为是从文件中读取数据的最快方法。但是如果我运行上面的代码,虽然缓冲区被正确填充,但性能太慢了(或者可能不是?你决定!!)我可以在 几乎 5 秒内读取那些 4194304 字节,那就是每秒小于 1MB。我正在使用 Eclipse 直接连接到我的 Optimus Dual 智能手机;即使我将读取操作置于循环中,读取也需要相同的时间(如果执行多次读取,可能不会发生开销初始化......不是这种情况)。

如果我减小或增大文件,这个文件大小与时间的关系不会改变:8 兆将在 9 秒内读取,2 兆将在 2 秒内读取,依此类推。 我读过,即使是慢速 SD 卡也可以以每秒至少 5 MB 的速度读取...... 请注意,4194304 是 2 值的幂,因为我已经读过这会提高性能。 请告诉我您的意见:现代智能手机的实际性能是每秒 1MB,还是我的代码有问题?谢谢

【问题讨论】:

  • 如果使用以下命令读取性能会更好:while(mappedByteBuffer.hasRemaining()) { mappedByteBuffer.get()); }; ?
  • 如果您需要对文件进行随机读/写访问,则内存映射文件是有意义的。如果您只需要在我使用普通的旧 Java io(可能是 nio 通道)后将数据读入内存。在有内存限制的移动平台上将 4 或 8MB 的文件读入内存也不是一个好主意。除此之外,我倾向于说有问题。 SD 卡(除非非常便宜)应该能够读取至少 2MB/s(2 级,仍然很便宜),手机内部存储应该更像 20MB/s。如果您想确保它不仅仅是硬件限制,请尝试使用不同的实现
  • 你有没有尝试过其他方法,看看能不能得到更好的表现?
  • @zapl :感谢您的提示,这实际上只是一个测试。在实际代码中,我将使用 512KB 左右的缓冲区。注意:我刚刚尝试过普通的 nio 通道,并且性能有所提高(??),现在我可以在一秒钟内读取近 2 兆字节。不完美,但确实更好!
  • @AndrzejDoyle:我做了那个测试,但并不走运,从/到 PC(通过 USB 连接到智能手机)的复制几乎是立即使用用于测试的 4 megs 文件完成的。所以,这不是硬件问题...

标签: java android performance file mapping


【解决方案1】:

在 Hotspot JVM 中,MappedByteBuffer.get() 使用内部调用而不是本机调用毫无价值。当复制大块数据块时,它一次复制多个字节,例如8 字节或更长的 MMX 指令。

AFAIK,Android 不这样做,这使得这个调用更加昂贵。

【讨论】:

  • 虽然我不怀疑您所说的是真的,但这并不能解释为什么读取率与 OP 观察到的一样低。至少,它不能是完整的答案。
  • 要测试硬件的性能,您可以尝试将文件复制到手机上或从 PC 复制文件(不是 Java)
【解决方案2】:

我看不出您的代码有什么问题。它可能只是设备和/或文件系统实现的速度。正如Tom Hawtin 所说,“[m] 内存映射 I/O 不会让您的磁盘运行得更快”。

【讨论】:

  • 毕竟,我们谈论的指令数量非常少,我认为它不能再优化了。我试图从原始项目中提取这些指令——包括多线程和锁定/解锁——然后我把它们放在一个几乎空的项目中,但我得到了相同的阅读时间
猜你喜欢
  • 2012-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-26
  • 1970-01-01
  • 1970-01-01
  • 2014-12-30
相关资源
最近更新 更多