2010-07-17 238 views
2

我在Windows(64位)和Linux(32位)上都試過下面的代碼。爲什麼FileOutputStream不會拋出OutOfMemoryException

我確信沒有BufferedOutputStream的代碼必然拋出OutOfMemoryException,但它沒有。

這是爲什麼?誰在做{緩存/緩衝/蒸汽}到磁盤?

如果與答案相關,請描述完整流程(Java API - >系統調用)嗎?

此代碼是否使用NIO?

/我困惑。

import java.io.DataOutputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 

public class WriteHugeFileToDisk { 
    private static int BYTE = 1; 
    private static int KILBYTE = BYTE * 1024; 
    private static int MEGABYTE = KILBYTE * 1024; 
    private static int GIGABYTE = MEGABYTE * 1024; 
    private static long TERABYTE = GIGABYTE * 1024L; 

    public static void main(String[] args) throws IOException { 
     FileOutputStream fileOutputStream = new FileOutputStream(args[0]); 
     DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream); 

     byte[] buffer = new byte[MEGABYTE]; 
     for(int i = 0; i < buffer.length; i++) { 
      buffer[i] = (byte)i; 
     } 

     for(long l = 0; l < 4000; l++) { 
      dataOutputStream.write(buffer); 
      ; 
     } 

    } 
} 

我跑這個代碼與Java 6.使用以下調用:

的Windows:

java WriteHugeFileToDisk %TEMP%\hi.txt 

的Linux:

java WriteHugeFileToDisk /mnt/hi.info 

請注意:該代碼創建4GB文件只是爲了測試。

回答

5

爲什麼會拋出OutOfMemoryException?它只是寫入磁盤。我不會感到驚訝,如果FileOutputStreamDataOutputStream一些緩衝(我沒有檢查),但他們肯定不需要緩衝一切你寫。

這段代碼並沒有直接使用NIO,但是如果內部的某些內容做到了,我不會感到驚訝。至於涉及哪些系統調用以及什麼時候 - 這將是特定於實現的,但重要的是要認識到,DataOutputStreamFileOutputStream都不是爲了緩衝所有內容。你寫了一些數據給他們,其中一些數據可能寫入磁盤。如果您刷新或關閉流,那麼您應該已經寫入到目前爲止的數據到全部。如果你不要刷新或關閉流,我希望只有相當小的數額(同樣,特定於實現)被緩存(如果有的話)。

請注意BufferedOutputStream確實介紹緩存 - 但只有你要求(或默認)。再次,它不會緩衝的一切,除非您根據數據要求提供儘可能多的緩衝區。

+0

好的答案,我只想補充說,緩衝的關鍵是性能。如果您寫入的每個字節都以寫入磁盤的操作結束,那將會很慢。如果你在磁盤上緩衝一個塊的等價物,這將是一個巨大的改進。如果你開始緩衝千兆字節的數據,你不會看到每增加幾兆字節的緩衝區大小都有很大的改進。 – 2010-07-17 21:53:25

+0

@Mattias:是的。當然,如果一個單獨的寫入調用已經*寫入了一個兆字節,那麼緩衝這些任何內容都沒有多大意義。 – 2010-07-17 21:55:01

1

緩衝流是一個流封裝器(很明顯)將數據緩存到內存,然後再將其傳遞到基礎流。當與文件流一起使用時,這會使您獲得更好的性能,因爲在讀取或寫入硬盤驅動器時會涉及很多開銷。緩衝功能使您可以通過將效率低下的多個讀取或寫入合併爲一個高效,更大的緩存來顯着減少讀取/寫入次數。然而,它是而不是對於您的應用程序的良好行爲至關重要。它只是幫助您減少對物理設備的訪問。

Java不能比其他語言更直接地訪問您的計算機的設備。在您的程序和硬盤上的位之間,仍有幾個層有權緩存或緩存Java拼命嘗試從磁盤獲取或緩存的任何內容。據我所知,操作系統可以(並且通常會)緩存或緩衝東西,而一些硬件也會這樣做。

在操作的Java意義上,緩衝與讀取或寫入設備或針對任何流的成功或失敗無關。

1

這兩條指令幾乎不消耗內存並打開文件句柄。

FileOutputStream fileOutputStream = new FileOutputStream(args[0]); 
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream); 

分配並填充1MB數據存儲在內存中的一個字節數組。

byte[] buffer = new byte[MEGABYTE]; 
for(int i = 0; i < buffer.length; i++) { 
    buffer[i] = (byte)i; 
} 

向輸出文件寫入這個1MB數據的4000倍。

for(long l = 0; l < 4000; l++) { 
    dataOutputStream.write(buffer); 
} 

結論:消耗1MB的內存和寫入到文件的4GB數據。所以除非你有很少的記憶,否則不能丟出OutOfMemoryException

1

誰在做{緩存/緩衝/蒸汽}到磁盤?

沒人。它直接寫入磁盤。沒有任何增量內存使用。

相關問題