虽然字符串的最大大小为〜0.75GB,但是Visual Studio显示5GB的使用量和运行的内存,为什么会有差异?

问题描述 投票:-1回答:1

此代码没有做任何实际的事情,我只是想知道会发生什么。

据我所知,唯一保留的两个变量是(最终)大字符串,以及跟踪字符串长度的大小可忽略的整数。

在我的机器上,字符串大约为0.75GB,此时将出现OutOfMemoryException。在此阶段,Visual Studio显示的使用量约为5GB。因此,我想知道为什么存在差异。

var initialText = "Test content";
var text = initialText;
var length = text.Length;
while (true)
{
    try
    {
        var currentLength = text.Length;
        Console.WriteLine($"Current Length - {currentLength}");
        Console.WriteLine($"Current Size in GB - {System.Text.Encoding.UTF8.GetByteCount(text)/1024.0/1024.0/1024.0}");
        text = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(text));
        Console.WriteLine($"Change In Size - {currentLength / (length + 0.0)}");
        length = currentLength;
    }
    catch (OutOfMemoryException)
    {
        break;
    }
}

作为第二个问题,根据任务管理器,当我开始运行代码时,我的机器大约有11GB的可用空间,当遇到异常时,它的容量增加了约3GB,这与上述数字不符。有什么想法吗?

c# memory memory-management out-of-memory heap
1个回答
0
投票

[首先,.net中的字符串是UTF-16单词的序列,因此每个char占用2个字节。要获取内存中字符串的大小(以字节为单位),您需要将其长度乘以2(忽略CLR实例标头)。

Console.WriteLine($"Current Size in GB - {text.Length * 2.0 /1024/1024/1024}");

另一个限制是.NET中的数组大小,请阅读@TheGenral中的备注here。您可以达到2个限制:最大大小(2GB)和最大索引。

下面是测试的修改版本:

var text = "Test content";
long length = text.Length;
try
{

    while (true)
    {
        var currentLength = text.Length;
        Console.WriteLine($"Current Length - {currentLength}");
        Console.WriteLine($"Current Size in GB - {text.Length * 2.0 / 1024 / 1024 / 1024}");
        text += new string('a', 500 * 1024*1024);
        length = currentLength;
        GC.Collect();
    }
}
catch (OutOfMemoryException e)
{
    Console.WriteLine(e);
}

StringBuilder版本差异:

var text = new StringBuilder("Test content");
...
text.Append('a', 500 * 1024*1024);

如果未启用gcAllowVeryLargeObjects,则将获得带有1B元素的OOM。

我无法使用字符串连接获得2B元素,但是如果您使用StringBuilder重做此测试,则可以达到2B个字符。在这种情况下,您将遇到第二个限制:数组不能容纳超过20亿个元素。 Here是有关上限的讨论。

this thread中讨论了最大字符串长度。

如果在Release模式下运行此代码,您将看到进程内存消耗几乎等于控制台输出中的字符串大小。

[我注意到并且无法解释的另一个有趣的事情是,在StringBuildergcAllowVeryLargeObjectsDebug模式下,我可以达到4GB,但是在Release模式下,它几乎达到了3GB。欢迎评论为什么会发生:)

© www.soinside.com 2019 - 2024. All rights reserved.