You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何为C#程序设置虚拟内存使用上限,超限时终止并抛出异常

给C#程序设置运行时内存上限并超限终止的方案

嘿,针对你这个大型C#程序要设置内存上限、超限自动终止的需求,我来给你几个实用的方案——毕竟手动在各处加PrivateMemorySize检查确实太折腾了,大型项目里根本顾不过来,很容易遗漏场景。


1. 后台线程全局监控(最省心的实现方式)

这个思路和你之前看到的循环检查类似,但我们把监控逻辑封装成一个独立的后台线程,程序启动时就跑起来,全程自动监控,完全不用在业务代码里埋点。

示例代码:

using System;
using System.Threading;

class MemoryMonitor
{
    private readonly long _maxMemoryBytes;
    private readonly Timer _monitorTimer;

    public MemoryMonitor(long maxMemoryMb)
    {
        // 强制最低100Mb,转换为字节单位
        _maxMemoryBytes = Math.Max(maxMemoryMb * 1024 * 1024, 100 * 1024 * 1024);
        // 每隔1秒检查一次(可根据需求调短,比如100ms,响应更快但略增CPU开销)
        _monitorTimer = new Timer(CheckMemoryUsage, null, TimeSpan.Zero, TimeSpan.FromSeconds(1));
    }

    private void CheckMemoryUsage(object state)
    {
        var currentProcess = System.Diagnostics.Process.GetCurrentProcess();
        // 这里可以选PrivateMemorySize64(私有内存,不包含共享部分)或WorkingSet64(物理内存占用),按需选择
        long currentMemory = currentProcess.PrivateMemorySize64;

        if (currentMemory > _maxMemoryBytes)
        {
            _monitorTimer.Dispose(); // 先停掉定时器,避免重复触发
            // 抛出自定义异常,或者直接终止程序,看你需求
            throw new OutOfMemoryException($"内存超限!当前使用:{currentMemory / (1024*1024)}Mb,限制:{_maxMemoryBytes/(1024*1024)}Mb");
            // 要是不想抛异常,直接终止也可以:Environment.Exit(1);
        }
    }

    public void StopMonitoring()
    {
        _monitorTimer?.Dispose();
    }
}

// 程序启动时初始化监控
class Program
{
    static void Main(string[] args)
    {
        // 从命令行参数读取内存限制,比如启动时传"200"就是200Mb,默认用最低100Mb
        long maxMemoryMb = 100;
        if (args.Length > 0 && long.TryParse(args[0], out var inputMb))
        {
            maxMemoryMb = inputMb;
        }

        // 使用using确保监控器能正确释放
        using var memoryMonitor = new MemoryMonitor(maxMemoryMb);

        // 这里放你的业务逻辑代码
        // 举个例子模拟内存暴涨:
        var memoryHog = new System.Collections.Generic.List<byte[]>();
        try
        {
            while (true)
            {
                memoryHog.Add(new byte[1024 * 1024]); // 每次加1Mb
                Console.WriteLine($"当前内存使用:{System.Diagnostics.Process.GetCurrentProcess().PrivateMemorySize64/(1024*1024)}Mb");
                Thread.Sleep(500);
            }
        }
        catch (OutOfMemoryException ex)
        {
            Console.WriteLine(ex.Message);
            Environment.Exit(1);
        }
    }
}

小提示:

  • 检查间隔可以灵活调整:如果对内存超限的响应速度要求高,就把间隔设短(比如100ms),但会增加一点点CPU占用,根据你的程序负载平衡就行。
  • 选对内存指标:PrivateMemorySize64是进程独占的内存,WorkingSet64是当前实际占的物理内存,你可以根据自己的监控需求选。

2. 操作系统层面的限制(适合部署场景)

如果你的程序是部署在服务器上,也可以直接用操作系统的工具来限制进程内存,这样更严格,不用改代码:

  • Windows:用「作业对象(Job Object)」来限制进程内存,C#可以通过P/Invoke调用Windows API实现,不过代码会复杂点,但能做到系统级的强制限制。
  • Linux:启动程序前用ulimit命令,比如ulimit -v 104857600 && dotnet YourApp.dll(100Mb的虚拟内存限制),或者用cgroup做更精细的资源管控,超限后系统会直接终止进程。

为什么不推荐手动在各处加检查?

大型项目里到处埋内存检查不仅繁琐,还容易漏场景,而且会把业务代码和监控代码混在一起,后期维护起来头疼。后台线程监控是非侵入式的,只需要启动时初始化一次,全程自动运行,完美适配你的场景。

最后别忘了强制最低100Mb的限制,代码里一定要做判断,别让用户设置低于这个值,不然程序可能刚启动就挂了。

内容的提问来源于stack exchange,提问作者HariUserX

火山引擎 最新活动