用户指定文件名和块大小。原始文件拆分为具有用户块大小的块(最后一个块除外)。对于每个块计算哈希函数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);
}
}
}
答案 0 :(得分:0)
在编写此类代码之前,您应该阅读一些关于.NET内部的书籍。您对.NET内存模型的理解是完全错误的,这就是您遇到此类错误的原因。 OutOfMemoryException
很少发生,如果你关心你的资源,特别是如果你正在处理数组。
你应该知道在.NET运行时有两个引用对象堆,基本对象和Large Objects Heap,它们之间最重要的区别是 LOH即使在垃圾之后也不会被压缩集合强>
你应该知道所有的阵列,甚至是小阵列,都会进入LOH,内存的消耗非常快。你也应该知道这一行:
part = null;
doesn't dispose memory不懈地。更糟糕的是,这一行根本没有做任何事情,因为你仍然可以引用你在队列中读取的文件部分。这就是你的记忆消失的原因。您可以尝试在每次哈希计算后调用GC
来解决此问题,但这是高度不推荐的解决方案。
您应该重写算法(这是Producer/Consumer
模式的非常简单的情况),而不是同时将整个文件内容存储在内存中。这很简单 - 只需将part
变量移出到静态字段,然后将下一个文件部分读入其中。在代码中引入EventWaitHandle
(或one of it's child classes)而不是队列,只需在阅读完文件的下一部分后立即计算下一个哈希。
我建议您通过阅读great series of Joe Albahari从C#中的线程基础开始,然后才尝试实现此类解决方案。祝你的项目好运。