2

我编写了一个dotnet分配内存的简单应用程序。它耗尽了机器上的所有物理内存,然后以OutOfMemoryException. 但是我的系统有一个交换文件,它从未被dotnet. 其他应用程序使用交换就好了。我玩过swappiness(60、100、1),但这没有效果。

我的理解是,Linux 上的进程可以消耗它想要的所有物理内存,如果没有剩余内存,则该内存将被写入交换文件/分区。只有当交换和物理内存都已满时,应用程序才会因 OOM 而崩溃。这是其他应用程序所做的,但不是dotnet应用程序。

我试过 dotnet core 3.1 和 5.0,使用的操作系统是 Ubuntu 20.04。

编辑:我的测试代码:

namespace TestProject
{
    class Program
    {
        static List<byte[]> l = new List<byte[]>();

        static void Main(string[] args)
        {
            while (true)
            {
                var b = new byte[100 * 1000 * 1024];
                l.Add(b);
            }
        }
    }
}
4

1 回答 1

3

好的,经过反复试验,我(或多或少)了解发生了什么。在上面的代码中,数组没有被完全分配,除非它的元素被“触摸”。Array.Fill<byte>(b, 0)我的意思是,除非我在将数组存储在静态列表中之前做了类似的事情,否则消耗的内存不是我所期望的。虽然我不知道这种行为,但似乎 dotnet 的一些延迟分配对于降低内存使用是有意义的(即在您要使用数组之前实际上不分配)。如果我使用,Array.Fill那么内存会更快地上升,最终会被分页交换。

那为什么我之前得到了OOM?我相信答案是我达到了静态列表的 2GB 对象大小。这是我不知道的限制,但在 dotnet 中,没有单个对象可以超过 2GB。使用上面的代码,我相信列表对象(内部数组、指向所有元素的指针等)已经用完足够的内存,它达到了 2GB 的限制并导致 OOM。

感谢所有阅读本文并提供反馈的人。

于 2021-01-26T14:26:15.027 回答