为什么C#处理2GB文件时会占用4GB内存?

3

我正在读取一个文件(这个文件包含一个2gb长的字符串)。

这是我的函数,它将文件的所有内容读入内存,然后拆分字符串并放置:

*reader = StreamReader
public List<char[]> GetAllContentAsList()
        {
            int bytesToRead = 1000000;
            char[] buffer = new char[bytesToRead];
            List<char[]> results = new List<char[]>();

            while (_reader.Read(buffer, 0, bytesToRead) != 0)
            {
                char[] temp = new char[bytesToRead];
                Array.Copy(buffer,temp,bytesToRead);
                results.Add(temp);
            }

            return results;
        }

当所有数据放入列表中时,它占用了4GB的RAM。当文件大小只有2GB时,这怎么可能呢?
*编辑
这就是我最终所做的。我没有将字节数组转换为字符串,而是直接传递字节并对其进行操作。这样,内存中仅使用2GB,而不是4GB。
 public List<byte[]> GetAllContentAsList()
            {
                int bytesToRead = 1000000;
                var buffer = new byte[bytesToRead];
                List<byte[]> results = new List<byte[]>();

                while (_reader.Read(buffer, 0, bytesToRead) != 0)
                {
                    //string temp = Encoding.UTF8.GetString(buffer);
                    byte[] b = new byte[bytesToRead];
                    Array.Copy(buffer,b,bytesToRead);
                    results.Add(b);
                }

                return results;
            }

1
你是如何得出List占用了4GB内存的结论的?单个对象的限制为2GB。你明白这行代码Array.Copy(buffer,temp,bytesToRead);会一直占用内存,直到垃圾回收器决定在你之后清理它吗? - Security Hound
你可以在C#中使用4GB吗? - Venson
4
顺便说一下,这是一种相当糟糕的读取数据的方式;最好使用流API(或基于读取器的API)。 - Marc Gravell
@Venson - 1.5GB 的限制是什麼?.NET 4.0 允許使用一個標誌來處理非常大的對象。甚至不清楚作者如何決定集合的內存使用情況。 - Security Hound
@Ramhound 我有很多图像的字节数组,当我尝试在程序中存储超过1GB到2GB的数据时,应用程序会因为OutOfMemory异常而崩溃。经过一段时间的搜索,我发现了一个MSDN帖子,描述了这是不可能成功实现的,但似乎LARGEADDRESSAWARE是这样一种解决方法,但它对我没有帮助...所以这篇文章(http://www.codeproject.com/Articles/483475/Memory-Limits-in-a-NET-Process)描述了甚至无法分配超过1.3GB的内存。 - Venson
显示剩余3条评论
1个回答

16

个人的猜测是:

这个文件采用UTF-8ASCII编码,并且只(或大部分)包含单字节宽度的字符(或者可能是其他大部分为单字节宽度的代码页)。

现在,.NET字符采用UTF-16编码,每个字符都有2个(或更多)字节的长度。

因此,在内存中,字符将会是原来的两倍大小。


+1 可以通过更改文件保存时的编码方式轻松进行测试。 - slugster
那可能就是这样了。Char 是16位(2字节)。 - Corak
1
@slugster - 当然可以,但是对于一个2GB的文件,我会留给你来测试 ;) - Oded
另外,如果我没记错的话,Array.Copy 可能会对内存产生影响(尽管这更多是在工作过程中而不是最终结果)。 - Brad Christie
此外,该列表将在操作过程中调整大小,并留下对象,GC可能在您查看内存使用情况时尚未收集。 - ta.speot.is
谢谢您的答案,解决了我的问题。我最终只是简单地传递字节而不是转换为字符。 - Ivan Bacher

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接