使用 .NET 核心设置内存限制

Posted

技术标签:

【中文标题】使用 .NET 核心设置内存限制【英文标题】:Putting memory limits with .NET core 【发布时间】:2021-11-15 02:32:40 【问题描述】:

我正在使用 ML.NET 构建一个用于二进制分类的 ML 应用程序。它将具有多个不同大小的 ML 模型(使用不同的训练数据构建),这些模型将作为 Blob 存储在 SQL Server 数据库中。客户端会随机发送物品到这个应用程序进行分类,并根据客户端ID,使用相应的模型进行分类。要对项目进行分类,需要从数据库中读取模型,然后将其加载到内存中。在内存中加载模型需要相当长的时间,具体取决于大小,我没有看到任何优化它的方法。因此,我计划将模型缓存在内存中。如果我缓存了许多重型模型,它可能会对内存造成压力,从而影响服务器上运行的其他进程的性能。所以没有直接的方法来限制缓存。所以寻找处理这个问题的建议。

【问题讨论】:

【参考方案1】:

产生一个新进程

在我看来,这是完成您想做的事情的唯一可行选择。生成一个与您的“主应用程序”通信(通过 IPC?)的全新进程。您可以使用此属性 https://docs.microsoft.com/en-us/dotnet/api/system.gcmemoryinfo.totalavailablememorybytes?view=net-5.0 设置内存限制,或者甚至可以使用 3rd-party-library(例如 https://github.com/lowleveldesign/process-governor),如果它达到特定数量的 RAM,它将终止您的进程。这两种方法都很粗糙,基本上会杀死你的进程。

如果您可以控制边车应用程序的运行,那么使用 Getting a process's ram usage 之类的东西真正监控 RAM 使用情况并优雅地停止进程可能是有意义的。

自己动手解决方案(不推荐)

基本上没有内置的方式来限制线程或类似的内存使用。

内存限制计入什么?

共享资源

由于您有一个正在运行的进程,您需要定义内存限制的确切数量。例如,如果您有一些由正在运行的线程操作的静态Dictionary - 它占用了什么?只有旧值和新值之间的差异?全新的价值?关键和价值?

还有更多这样的情况需要您考虑。

实测

您需要某种方法来计算实际内存使用量。这可能很难/几乎不可能“实施”:

需要引用计数吗?

如果你有一个敌对线程,它可能会产生对一个对象的无限量的引用,没有使用new 关键字。对于每个引用,您必须计算 32/64 位。

内置类型呢?

测量包含在您自己的类型定义中的byte[] 可能“容易”,但是内置类呢?如果有人初始化一个 100MB 的字符串,这可能是您需要跟踪的数量。

...还有更多...

正如您在之前的示例中可能注意到的那样,“线程使用的 RAM”没有简单的定义。这就是它的价值也不容易获得的原因。

在我看来,做这样的事情非常复杂,需要在你身边做很多定义工作。 很多 的努力可能是可行的,但我不确定这是否真的是你想要的。即使你设法 - 你会怎么做?仅杀死线程可能无法清理资源。

因此,我真的会考虑拥有一个由操作系统管理的独立进程,您可以随时杀死它。

【讨论】:

【参考方案2】:

您的模型有多大?即使是 100meg+ 的大型模型,也可以很快从快速/SSD 存储中加载。我会考虑将它们缓存在快速驱动器/SSD 上,因为退出 SQL Server 将比原始磁盘慢得多。看看这是否有助于您的表现。

【讨论】:

以上是关于使用 .NET 核心设置内存限制的主要内容,如果未能解决你的问题,请参考以下文章

Asp.net Core 中的内存使用限制

Docker容器生产实践1——永远设置容器内存限制

如何设置java内存限制

如何限制Linux内存的使用

Docker 运行时资源限制

Docker 运行时资源限制