2012-11-20 35 views
6

我想了解是否從MappedByteBuffer類的get()方法獲得的性能是否正常。我的代碼如下:Java 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卡數據的最快方法,我看了文檔,我發現文件映射被認爲是,在許多情況下,從文件中讀取最快的方法。但是如果我運行上面的代碼,雖然緩衝區是正確填充的,但是性能很慢(或者可能不是?你決定!!)我可以在中讀取那些4194304字節差不多5秒,即小於1MB每次第二個。我使用直接連接到Optimus Dual智能手機的Eclipse;即使我把讀取操作放在一個循環中也需要同一時間(如果執行多次讀取,可能不會發生開銷初始化...不是這種情況)。

如果我縮小或放大文件,此文件大小關係不會改變:將在近9秒內讀取8個字節,在2秒內讀取2個字節等等。 我讀過,即使是一個慢速的SD卡可以以至少每秒5 MB的速度讀取... 請注意,4194304是2值的冪,因爲我讀過這會提高性能。 請告訴我您的意見:現代智能手機的實際性能是每秒1MB,還是我的代碼有問題?謝謝

+0

如果您閱讀以下內容,性能會更好:while(mappedByteBuffer.hasRemaining()) { mappedByteBuffer.get()); }; ? –

+1

如果您需要對文件進行隨機讀取/寫入訪問,內存映射文件是有意義的。如果您只是需要將數據讀入內存中,那麼我會使用普通的Java io(也許是nio頻道)。在具有內存限制的移動平臺上將4或8MB文件讀入內存也不是一個好主意。除此之外,我傾向於說有什麼不對。 SD卡(除非很便宜)應該能夠讀取至少2MB/s(2級,仍然非常便宜),而手機內部存儲應該更像20MB/s。如果您想確保它不僅僅是硬件限制 – zapl

+0

您是否嘗試其他方法以查看您是否可以獲得更好的性能,請嘗試使用不同的實現方法? – njzk2

回答

1

我看不出你的代碼有什麼問題。這可能只是設備和/或文件系統實施的速度。正如Tom Hawtin所說的那樣:「[m]內存映射I/O不會讓你的磁盤運行得更快」。

+0

畢竟,我們談論的是非常少量的指令,我認爲它不可能更優化。我試圖從原始項目中抽出這些說明 - 包括多線程和鎖定/解鎖 - 我把它們放在一個幾乎空的項目中,但我得到了相同的閱讀時間 – Logicat

3

它在Hotspot JVM中沒有任何價值,MappedByteBuffer.get()使用內部調用而不是本地調用。當複製大段數據塊時,它一次複製多個字節,使用MMX指令8個字節或更長。

AFAIK,Android沒有這樣做,這使得這個通話更加昂貴。

+0

雖然我不懷疑你說的是真的這並不能解釋爲什麼讀取速率與OP觀察到的一樣低。至少,這不可能是完整的答案。 –

+1

爲了測試硬件的性能,您可以嘗試在手機上或從PC上覆制文件(而不是在Java中) –