[英]Memory leak with an array c#
用户指定文件名和块大小。 原始文件以用户块大小拆分成块(最后一个块除外)。 对于每个块计算哈希函数SHA256
并写入控制台。
这是一个有 2 个线程的程序:第一个线程读取原始文件并放入块的队列字节数组中; 第二个线程从队列中删除块的字节数组并计算哈希。
在第一次迭代之后,直到程序完成,内存才会处理。
在下一次迭代中,内存正常分配和处置。
因此,在下一次读取部分数组时,我得到OutOfMemoryException
。
如何正确管理内存以避免内存泄漏?
class Encryption
{
static FileInfo originalFile;
static long partSize = 0;
static long lastPartSize = 0;
static long numParts = 0;
static int lastPartNumber = 0;
static string[] hash;
static Queue<byte[]> partQueue = new Queue<byte[]>();
public Encryption(string _filename, long _partSize)
{
try
{
originalFile = new FileInfo(@_filename);
partSize = _partSize;
numParts = originalFile.Length / partSize;
lastPartSize = originalFile.Length % partSize;
if (lastPartSize != 0)
{
numParts++;
}
else if (lastPartSize == 0)
{
lastPartSize = partSize;
}
lastPartNumber = (int)numParts - 1;
hash = new string[numParts];
}
catch (FileNotFoundException fe)
{
Console.WriteLine("Error: {0}\nStackTrace: {1}", fe.Message, fe.StackTrace);
return;
}
catch (Exception e)
{
Console.WriteLine("Error: {0}\nStackTrace: {1}", fe.Message, fe.StackTrace);
}
}
private void readFromFile()
{
try
{
using (FileStream fs = new FileStream(originalFile.FullName, FileMode.Open, FileAccess.Read))
{
for (int i = 0; i < numParts; i++)
{
long len = 0;
if (i == lastPartNumber)
{
len = lastPartSize;
}
else
{
len = partSize;
}
byte[] part = new byte[len];
fs.Read(part, 0, (int)len);
partQueue.Enqueue(part);
part = null;
}
}
}
catch(Exception e)
{
Console.WriteLine("Error: {0}\nStackTrace: {1}", fe.Message, fe.StackTrace);
}
}
private static void hashToArray()
{
try
{
SHA256Managed sha256HashString = new SHA256Managed();
int numPart = 0;
while (numPart < numParts)
{
long len = 0;
if (numPart == lastPartNumber)
{
len = lastPartSize;
}
else
{
len = partSize;
}
hash[numPart] = sha256HashString.ComputeHash(partQueue.Dequeue()).ToString();
numPart++;
}
}
catch (Exception e)
{
Console.WriteLine("Error: {0}\nStackTrace: {1}", fe.Message, fe.StackTrace);
}
}
private void hashWrite()
{
try
{
Console.WriteLine("\nResult:\n");
for (int i = 0; i < numParts; i++)
{
Console.WriteLine("{0} : {1}", i, hash[i]);
}
}
catch(Exception e)
{
Console.WriteLine("Error: {0}\nStackTrace: {1}", fe.Message, fe.StackTrace);
}
}
public void threadsControl()
{
try
{
Thread readingThread = new Thread(readFromFile);
Thread calculateThread = new Thread(hashToArray);
readingThread.Start();
calculateThread.Start();
readingThread.Join();
calculateThread.Join();
hashWrite();
}
catch (Exception e)
{
Console.WriteLine("Error: {0}\nStackTrace: {1}", fe.Message, fe.StackTrace);
}
}
}
在编写此类代码之前,您应该阅读一些有关 .NET 内部结构的书籍。 您对 .NET 内存模型的理解完全错误,这就是您收到此类错误的原因。 如果您关心您的资源,尤其是在处理数组时, OutOfMemoryException
很少发生。
您应该知道,在 .NET 运行时中,引用对象有两种堆,基本的一种和大对象堆,它们之间最重要的区别是即使在垃圾收集之后 LOH 也不会被压缩。
你应该知道所有的数组,即使是小的数组,都会进入 LOH,内存消耗非常快。 你也应该知道这一行:
part = null;
不会立即处理内存。 更糟糕的是,这一行根本没有做任何事情,因为您仍然可以引用您在队列中读取的文件部分。 这就是你的记忆消失的原因。 您可以尝试通过在每次哈希计算后调用GC
来解决此问题,但这是强烈不推荐的解决方案。
您应该重写您的算法(这是Producer/Consumer
模式的非常简单的情况),而不要同时将整个文件内容存储在内存中。 这很容易 - 只需将您的part
变量移出静态字段,然后将下一个文件部分读入其中。 在您的代码而不是队列中引入EventWaitHandle
(或其子类之一),并在您阅读文件的下一部分后立即计算下一个哈希。
我建议您通过阅读Joe Albahari的精彩系列,从 C# 线程的基础知识开始,然后才尝试实现此类解决方案。 祝你的项目好运。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.