System.OutOfMemoryException on server side for client files
我正在从客户端获取数据并将其保存到本地主机上的本地驱动器。我已经检查了它的 221MB 文件,但对 1Gb 文件的测试给出了以下异常:
An unhandled exception of type 'System.OutOfMemoryException' occurred in mscorlib.dll
以下是服务器端的异常代码。
更新
服务器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | public void Thread() { TcpListener tcpListener = new TcpListener(ipaddr, port); tcpListener.Start(); MessageBox.Show("Listening on port" + port); TcpClient client=new TcpClient(); int bufferSize = 1024; NetworkStream netStream; int bytesRead = 0; int allBytesRead = 0; // Start listening tcpListener.Start(); // Accept client client = tcpListener.AcceptTcpClient(); netStream = client.GetStream(); // Read length of incoming data to reserver buffer for it byte[] length = new byte[4]; bytesRead = netStream.Read(length, 0, 4); int dataLength = BitConverter.ToInt32(length,0); // Read the data int bytesLeft = dataLength; byte[] data = new byte[dataLength]; while (bytesLeft > 0) { int nextPacketSize = (bytesLeft > bufferSize) ? bufferSize : bytesLeft; bytesRead = netStream.Read(data, allBytesRead, nextPacketSize); allBytesRead += bytesRead; bytesLeft -= bytesRead; } // Save to desktop File.WriteAllBytes(@"D:\\LALA\\Miscellaneous" + shortFileName, data); // Clean up netStream.Close(); client.Close(); } |
我首先从客户端获取文件大小,然后是数据。
1).我应该增加缓冲区大小或任何其他技术吗?
2)。
在将其写入磁盘之前,您无需将整个内容读入内存。只需直接从网络流复制到
1 2 3 4 5 6 7 8 9 10 | byte[] length = new byte[4]; // TODO: Validate that bytesRead is 4 after this... it's unlikely but *possible* // that you might not read the whole length in one go. bytesRead = netStream.Read(length, 0, 4); int bytesLeft = BitConverter.ToInt32(length,0); using (var output = File.Create(@"D:\\Javed\\Miscellaneous" + shortFileName)) { netStream.CopyTo(output, bytesLeft); } |
请注意,您应该使用
1 2 3 4 | using (Stream netStream = ...) { // Read from it } |
这样即使抛出异常,流也会被关闭。
发生"内存不足"异常是因为您试图在将整个文件转储到磁盘之前将其放入内存。这是次优的,因为您不需要内存中的整个文件来写入文件:您可以以合理大小的增量逐块读取它,然后随时写出。
从 .NET 4.0 开始,您可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | // Read and ignore the initial four bytes of length from the stream byte[] ignore = new byte[4]; int bytesRead = 0; do { // This should complete in a single call, but the API requires you // to do it in a loop. bytesRead += netStream.Read(ignore, bytesRead, 4-bytesRead); } while (bytesRead != 4); // Copy the rest of the stream to a file using (var fs = new FileStream(@"D:\\Javed\\Miscellaneous" + shortFileName, FileMode.Create)) { netStream.CopyTo(fs); } netStream.Close(); |
从 .NET 4.5 开始,您也可以使用
注意从流中删除前四个字节的代码。这样做是为了避免将流的长度与"有效负载"字节一起写入。如果您可以控制网络协议,则可以更改发送方以停止为其长度添加前缀,并删除在接收方读取并忽略它的代码。
CLR 对每个对象的限制略低于 2GB。然而这是理论上的,实际上你可以分配多少内存取决于框架允许你分配多少内存。我不希望它允许您分配 1 GB 数据表。您应该分配较小的表,并将数据分块写入磁盘文件。