内存泄漏与数组c#

时间:2016-10-06 22:41:52

标签: c# arrays multithreading out-of-memory

用户指定文件名和块大小。原始文件拆分为具有用户块大小的块(最后一个块除外)。对于每个块计算哈希函数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);
        }
    }
}

1 个答案:

答案 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#中的线程基础开始,然后才尝试实现此类解决方案。祝你的项目好运。