2012-09-06 105 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 
}