为什么 ASP Net Core 2.2 不释放内存?

Kev*_*aja 29 c# memory-leaks asp.net-web-api asp.net-core

我正在使用以下默认项目测试 ASP Net Core 2.2:

Visual Studio > 文件 > 新建 > 项目 > ASP NET Core Web 应用程序 > 下一步 > 创建。按界面上的IIS Express按钮,自动跳转到https://localhost:44356/api/values

编辑:关键是,我正在测试 ASP Net Core,以防有人暴力发送垃圾邮件。

我只修改了这个:

        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] { "value1", "value2" };
        }
Run Code Online (Sandbox Code Playgroud)

编辑:为此,我编辑了我的代码以进行合理的测试,生成最小的可重现示例

// GET api/values

[HttpGet]
public ActionResult<IEnumerable<Post>> Get()
{
    // Testing for brute force
    return Enumerable.Range(0, 100).Select(x => "Example Value").ToList();
}
Run Code Online (Sandbox Code Playgroud)

起始进程内存为 80 MB。

但是,当我尝试刷新页面时,起始内存不断出现: 编辑测试

编辑:原来这个问题从 2 年前就存在了,没有解决方案,还有真实生活示例经验https://github.com/aspnet/AspNetCore/issues/1976

我很确定黄色箭头表示 GC 工作正常,但我的进程内存使用量并没有下降每个请求。我不确定这是来自 ASP Net Core 的功能还是错误,我预计它会在请求后下降/每次用户获取 /values 时都不会增加

编辑:我不希望人们危险地向我的应用程序发送垃圾邮件,并且由于内存泄漏而开始崩溃。如果此解决方案尚未修复,我害怕为我的公司使用 Net Core。

为什么 ASP Net Core 2.2 不释放内存?

我试过在两台不同的笔记本电脑上测试,结果是一样的。

编辑:我的同事也有这个问题。

编辑:我尝试使用 dot net core v2.1,结果是一样的。

我试过 GCCollect(); 结果是一样的。

旧图像参考。

启动进程内存

进程内存不断出现

sch*_*nyw 34

ASP.NET Core 使用的内存似乎比应有的多,因为它默认配置为使用服务器 GC(而不是工作站 GC)。有关类似问题的讨论,请参见此处。理论上,当您的服务器面临内存压力时,应用程序应该能够减少其内存占用。

这个 MSDN docGithub CoreCLR doc 中有更多关于这个主题的信息。

要查看是否确实是服务器 GC 导致了额外的内存消耗,您可以在 csproj 文件中将 GC 策略设置为工作站:

<PropertyGroup> 
    <ServerGarbageCollection>false</ServerGarbageCollection>
</PropertyGroup>
Run Code Online (Sandbox Code Playgroud)

  • 感谢你的回答!真的很有帮助! (3认同)

tur*_*kik 13

!!!最后编辑:这个解决方案不是最好的方法,有些人可能会说这是一个可怕的解决方案......我推荐下面的答案!!!

我正在努力解决同样的问题。经过一些研究,我发现 .NET Core 会尽可能分配新的内存空间。如果需要,它会被释放,但是这个释放比另一个释放需要更多的资源,因为你必须以这种方式使用 GC:

GC.Collect(2, GCCollectionMode.Forced, true);
GC.WaitForPendingFinalizers();
Run Code Online (Sandbox Code Playgroud)

我的解决方案是创建一个中间件:

using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace RegisterValidator
{
    public class GCMiddleware
    {
        private readonly RequestDelegate _next;

        public GCMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext httpContext)
        {
            await _next(httpContext);
            GC.Collect(2, GCCollectionMode.Forced, true);
            GC.WaitForPendingFinalizers();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:此中间件将GC.Collect在每次调用后提供。

并在Configure()方法中注册它Startup.cs

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider service, ILoggerFactory loggerFactory)
    {

        app.UseMiddleware<GCMiddleware>();
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseStaticFiles();
        //app.UseHttpsRedirection();
        app.UseMvcWithDefaultRoute();

        app.Run(async (context) =>
        {
            await context.Response.WriteAsync("\"No ");

        });
    }
Run Code Online (Sandbox Code Playgroud)

也许还有另一种解决方案,但我还没有找到。我希望它有帮助。

编辑:如果您不确定内存使用情况是因为存在大量其他问题的分配空间,您可以使用dotMemory,它会比您的 Visual Studio 更详细地分析您的内存使用情况。

  • 这是一个糟糕的解决方案。不要使用它。 (16认同)
  • 对每个请求强制收集对性能来说非常糟糕 (2认同)