为什么队列要消耗这么多内存?

时间:2019-07-18 10:26:28

标签: c# memory queue

基本上,在开始编码之前,我在codewars网站上做了一个code kata有点“热身”,并注意到一个问题,我不知道是因为我的代码还是正常的事情。

public static string WhoIsNext(string[] names, long n)
{
    Queue<string> fifo = new Queue<string>(names);

    for(int i = 0; i < n - 1; i++)
    {
        var name = fifo.Dequeue();
        fifo.Enqueue(name);
        fifo.Enqueue(name);
    }
    return fifo.Peek();
}

被这样称呼:

// Test 1
string[] names = { "Sheldon", "Leonard", "Penny", "Rajesh", "Howard" };
long n = 1; 
var nth = CodeKata.WhoIsNext(names, n); // n = 1 Should return sheldon.

// test 2
string[] names = { "Sheldon", "Leonard", "Penny", "Rajesh", "Howard" };
long n = 52; 
var nth = CodeKata.WhoIsNext(names, n); // n = 52 Should return Penny.

// test 3
string[] names = { "Sheldon", "Leonard", "Penny", "Rajesh", "Howard" };
long n = 7230702951; 
var nth = CodeKata.WhoIsNext(names, n); // n = 52 Should return Leonard.

在此代码中,当我将长n设置为7230702951(一个非常高的数字...)时,它将引发内存不足异常。是数字 高,还是只是未针对此类数字优化的队列。

之所以这样说,是因为我尝试使用列表,并且列表内存使用量保持在500 MB以下(平台约为327MB btw),并且运行了大约2/3分钟,而队列在几秒钟内引发了异常,仅在那个时候就超过了2GB。

有人问我为什么会发生这种情况吗?

修改1

我忘记添加列表代码:

public static string WhoIsNext(string[] names, long n)
{
    List<string> test = new List<string>(names);
    for(int i = 0; i < n - 1; i++)
    {
        var name = test[0];
        test.RemoveAt(0);

        test.Add(name);
        test.Add(name);
    }

    return test[0];
}

修改2

对于那些说代码将名称加倍并且效率低下的人来说,我已经知道,代码并不是有用的,只是一个kata。 (我现在更新了链接!)

我的问题是,为什么Queue如此低效,以至于List的计数很高?

1 个答案:

答案 0 :(得分:2)

部分原因是队列代码比List代码快 way ,因为队列是循环缓冲区,因此对删除进行了优化。 列表不是-每次删除第一个元素时,列表复制数组内容

例如,将输入值更改为72307000。在我的机器上,队列在不到一秒钟的时间内完成了任务。该列表仍在等待几分钟(以这个速度,几小时)消失。 在4分钟之内,i的电话是752408-它完成了将近1%的工作。

因此,我不确定队列的内存效率较低。 如此之快,您很快就会遇到内存问题。该列表几乎肯定有相同的问题(ListQueue进行数组大小加倍的方式非常相似)-可能要花几天的时间。

在某种程度上,即使没有运行代码,您也可以预测 。其中包含7230702951条目(运行64位)的队列将每个条目占用8个字节的 minimum (最小)。因此57845623608字节。大于50GB。显然,您的机器将很难将其装入RAM(加上.NET不会让您拥有如此大的阵列)...

此外,您的代码还有一个细微的错误。 循环永远不会结束(如果n大于int.MaxValue)。您的循环变量是int,但参数是long。您的int将溢出(int.MaxValueint.MinValuei++)。因此,对于n较大的值,循环将永远不会退出(这意味着队列将永远增长)。您可能应该将i的类型更改为long