2012-09-06 104 views
0

好的,我製作了一個C#winform應用程序,它是一個File_Splitter_Joiner。 你只要給它一個文件,它會將它分割成你指定的許多部分。 拆分是在一個單獨的線程中完成的。 一切都很好,直到我切片1Gig文件! 在任務管理器中,我看到我的程序開始消耗1G內存,而且我的電腦幾乎死亡! 不僅如此,當切片完成後,消費並沒有改變! (不知道如果這意味着垃圾收集器不工作,雖然我很確定我丟失了所有引用大數據塊的東西,所以它應該工作) 這是Splitter構造函數(只是爲了給你一個更好的主意):內存管理和程序性能問題

public FileSplitter(string FileToSplitPath, string PiecesFolder, int NumberOfPieces, int PieceSize, SplittingMethod Method) 
{ 
    FileToSplitInfo = new FileInfo(FileToSplitPath); 
    this.FileToSplitPath = FileToSplitPath; 
    this.PiecesFolder = PiecesFolder; 
    this.NumberOfPieces = NumberOfPieces; 
    this.PieceSize = PieceSize; 
    this.Method = Method; 
    SplitterThread = new Thread(Split); 
} 

這裏是做了實際的分割方法: (我還是個新手,那麼你將會看到「可能不會」以最好的方式來完成我只是在這裏學習)

private void Split() 
{ 
    int remainingSize = 0; 
    int remainingPos = -1; 
    bool isNumberOfPiecesEqualInSize = true; 
    int fileSize = (int)FileToSplitInfo.Length; // FileToSplitInfo is a FileInfo object 
    if (fileSize % PieceSize != 0) 
    { 
    remainingSize = fileSize % PieceSize; 
    remainingPos = fileSize - remainingSize; 
    isNumberOfPiecesEqualInSize = false; 
    } 
    byte[] fileBytes = new byte[fileSize]; 
    var _fs = File.Open(FileToSplitPath, FileMode.Open); 
    BinaryReader br = new BinaryReader(_fs); 
    br.Read(fileBytes, 0, fileSize); 
    br.Close(); 
    _fs.Close(); 

    for (int i = 0, index = 0; i < NumberOfPieces; i++, index += PieceSize) 
    { 
    var fs = File.Create(PiecesFolder + "\\" + Path.GetFileName(FileToSplitPath) + "." + (i+1).ToString()); 
    var bw = new BinaryWriter(fs); 
    bw.Write(fileBytes, index, PieceSize); 
    if(i == NumberOfPieces-1 && !isNumberOfPiecesEqualInSize && Method == SplittingMethod.NumberOfPieces) 
    bw.Write(fileBytes, remainingPos, remainingSize); 
    bw.Close(); 
    fs.Close(); 
    } 
MessageBox.Show("File has been splitted successfully!"); 
SplitterThread.Abort(); 
} 

現在,而不是通過一個二進制文件讀取文件的字節yReader,我通過File.ReadAllBytes方法第一次讀取它,它工作正常,文件很小,但是,我得到了一個「SystemOutOfMemory」異常,當我處理我們的大個子時,不知道爲什麼我沒有得到這個例外時我通過BinaryReader讀取字節。

(這是問題之間的)

所以,主要的問題是,我怎麼能在不消耗這麼多的內存的方式加載大文件(演出而言)?我的意思是,我怎麼讓我的程序不消耗所有的內存? 以及如何在分割完成後釋放使用過的內存? (我實際使用

bw.Dispose; fs.Dispose; 

,而不是

bw.Close(); fs.Close(); 

是一樣的。 我知道將q可能沒有什麼意義,因爲當我們加載的東西,它在我們的記憶變得沒有別的地方,但是,我這樣問的原因是因爲我使用了另一個Splitting_Joining程序(不是我寫的),只是爲了看看它是否有同樣的問題,我加載了該文件,該程序消耗了大約5M的RAM,當我開始分裂,它使用了大約10Migs !! 現在,這是一個非常大的差異..可能是應用程序在C/C++ ..

那麼總結一下,誰吸?它是我的代碼,如果是的話,我該如何解決它?還是C#當涉及到性能?

謝謝SOOO多的東西,你可以幫我了:)

+0

沒事做的問題,而是分裂的過去分詞是分裂的,而不是分裂。 :) –

回答

1

有可以做出不同的方面更好:

  • 如果您正在使用大文件,工作爲什麼第一次讀全部裏面的數組和寫入另一個文件?只要在讀取另一個文件的同時寫入新文件即可。

  • 使用using保證處置流,在任何情況下:或者有例外或沒有例外。

  • 如果你開始使用真正的大文件,如1GB或更多,我會建議看看Memory Mapped Files。因此,您將利用令人難以置信的內存消耗優勢以及更高的性能成本。

2

下面兩行會基爾加丹你:當大小超過Int32.MaxValue

int fileSize = (int)FileToSplitInfo.Length; // a FileInfo object 
... 
byte[] fileBytes = new byte[fileSize]; 
  1. 你的代碼將失敗。不必要的,只需使用long fileSize = FileToSplitInfo.Length;
  2. 當沒有足夠的內存連接時,此更正的代碼將失敗。碎片化(LOH)會遲早會讓你失望。
  3. 您爲整個文件分配內存,但一次只需要PieceSize個字節。

你甚至都不需要知道檔案大小,只是

byte[] pieceBuffer = new byte[PieceSize]; 

while (true) 
{ 
    int nBytes = br.Read(pieceBuffer, 0, pieceBuffer.Length); 
    if (nBytes == 0) 
     break; 

    // write this piece, the length is nBytes 
}