You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quartz.Net任务执行时内存持续增长致OutOfMemoryException求助

排查Quartz.Net结合PostgreSQL的内存泄漏问题

问题描述

在.NET API项目中使用Quartz.Net调度任务,结合PostgreSQL存储任务和触发器,任务的创建、删除、执行均正常,但程序运行时内存占用持续增长,一段时间后抛出OutOfMemoryException并崩溃。通过Rider监控发现存在未释放的服务或类,尝试自定义JobFactory、将任务/JobFactory/IScheduler注册为单例等方案后仍未解决。

环境配置

NuGet包

<PackageReference Include="Quartz" Version="3.13.1" />
<PackageReference Include="Quartz.AspNetCore" Version="3.13.1" />
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.13.1" />
<PackageReference Include="Quartz.Serialization.Json" Version="3.13.1" />
<PackageReference Include="Npgsql" Version="8.0.6" />

appsettings.json配置

"ConnectionStrings": {
    "DefaultConnection": "User ID=postgres;Password=postgres;Server=localhost;Port=5432;Database=postgre_db"
},
"Quartz": {
    "quartz.scheduler.instanceName": "default",
    "quartz.jobStore.type": "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz",
    "quartz.jobStore.driverDelegateType": "Quartz.Impl.AdoJobStore.PostgreSQLDelegate, Quartz",
    "quartz.jobStore.tablePrefix": "QRTZ_",
    "quartz.jobStore.dataSource": "default",
    "quartz.dataSource.default.connectionStringName": "DefaultConnection",
    "quartz.dataSource.default.provider": "Npgsql",
    "quartz.jobStore.useProperties": "true",
    "quartz.serializer.type": "newtonsoft"
}

Program.cs配置

// Read configurations in appsettings.json
builder.Services.Configure<QuartzOptions>(builder.Configuration.GetSection("Quartz"));

// Use Quartz
builder.Services.AddQuartz(configurator =>
{
    configurator.UsePersistentStore(options =>
    {
        options.UsePostgres(builder.Configuration.GetConnectionString("DefaultConnection")!);
        options.UseNewtonsoftJsonSerializer();
    });

    // Create a job and trigger
    JobKey jobFromProgram = new("JobFromProgram");
    configurator.AddJob<SimpleJob>(jobFromProgram);
    configurator.AddTrigger(trigger => trigger.ForJob(jobFromProgram)
        .WithIdentity("JobFromProgramTrigger")
        .WithCronSchedule("*/5 * * ? * *")); // Run every 5 seconds

});

builder.Services.AddQuartzHostedService(options =>
{
    options.WaitForJobsToComplete = true;
});

任务类

public class SimpleJob(ILogger<SimpleJob> logger) : IJob
{
    public Task Execute(IJobExecutionContext context)
    {
        logger.LogInformation($"{context.JobDetail.Key.Name} executed! {DateTime.Now}");
        return Task.CompletedTask;
    }
}

已尝试方案

  • 自定义JobFactory并注册:
public class SimpleJobFactory(IServiceProvider serviceProvider) : IJobFactory
{
    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        return (IJob)serviceProvider.GetRequiredService(bundle.JobDetail.JobType);
    }

    public void ReturnJob(IJob job) { }
}

// 在Program.cs的AddQuartz中使用:
configurator.UseJobFactory<SimpleJobFactory>();
  • 将任务、JobFactory及IScheduler注册为单例:
builder.Services.AddSingleton<SimpleJob>().AddSingleton<SimpleJobFactory>();
builder.Services.AddSingleton(provider => provider.GetRequiredService<ISchedulerFactory>().GetScheduler().GetAwaiter().GetResult());

排查建议

  1. 检查Npgsql连接泄漏

    • 开启Npgsql连接日志,确认Quartz的ADO JobStore是否正确管理数据库连接,查看是否存在未释放的连接。
    • 排查项目中其他涉及Npgsql的操作,确认是否手动创建连接后未释放。
  2. 优化Job实例生命周期管理

    • 若Job依赖的服务存在生命周期冲突(如单例服务持有短生命周期服务引用),会导致对象无法被GC回收。
    • 若Job实现了IDisposable接口,需在自定义JobFactory的ReturnJob方法中调用Dispose释放资源。
  3. 序列化配置调整

    • 尝试切换到System.Text.Json序列化(Quartz支持),对比内存占用变化,排查NewtonsoftJson是否存在内存泄漏问题。
    • 确认quartz.jobStore.useProperties设置的合理性,若JobDataMap中存储大量复杂对象,需简化数据结构。
  4. 深入内存分析

    • 使用Rider内存快照功能,捕获内存占用高的对象,跟踪其引用链,定位被Quartz或DI容器持有的未释放对象。
    • 检查静态变量是否持有Job实例或服务引用,导致GC无法回收。
  5. Quartz配置优化

    • 调整Quartz线程池大小(quartz.threadPool.threadCount),避免过多线程持有资源未释放。
    • 降低Quartz日志级别,避免大量日志输出导致内存占用增长。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 04:51:00