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

Django中aiohttp异步HTTP请求的内存泄漏问题排查与优化

Django + aiohttp 异步请求内存泄漏问题解决方案

1. 内存泄漏的可能原因

  • ClientSession 未正确复用/关闭:每次请求新建ClientSession且未关闭,会残留连接池、TCP连接等资源,长期累积占用内存。
  • 孤儿异步任务:用asyncio.create_task创建的任务未被await,或任务抛出异常未捕获,导致任务对象及其引用的资源无法被GC回收。
  • Django 上下文残留:异步视图中引用的request对象、ORM实例等上下文未被正确销毁,若异步任务持有这些对象的引用,会导致内存无法释放。
  • 连接池配置不合理:TCPConnector的连接数限制过高,或未开启关闭连接的自动清理,导致大量空闲keep-alive连接长期占用内存。
  • 依赖版本bug:部分Python 3.9/3.10/3.12与对应aiohttp版本的组合存在已知内存泄漏问题,或第三方解析库(如json、xml处理库)本身存在泄漏。
  • 全局数据堆积:用全局列表、字典存储请求结果或中间数据,未及时清理,导致数据量持续增长。

2. aiohttp 内存管理优化措施

  • 复用全局ClientSession:在Django应用启动时初始化一个全局ClientSession,所有异步请求复用该实例,应用关闭时调用session.close()销毁。
  • 优化连接池配置:使用TCPConnector限制连接数,开启自动清理:
    connector = aiohttp.TCPConnector(
        limit=100,          # 全局最大连接数
        limit_per_host=20,  # 单主机最大连接数
        enable_cleanup_closed=True  # 自动清理已关闭的连接
    )
    session = aiohttp.ClientSession(connector=connector)
    
  • 显式管理响应对象:始终用async with语法处理请求,确保响应体被正确关闭:
    async with session.get(url) as resp:
        data = await resp.json()
    
  • 清理异步任务:所有异步任务必须被await,批量任务用asyncio.gather并捕获异常,避免任务成为孤儿:
    tasks = [fetch_data(session, url) for url in urls]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    # 处理异常结果,避免残留未处理的异常对象
    
  • 禁用不必要功能:若不需要keep-alive,设置connector=aiohttp.TCPConnector(force_close=True);关闭自动重试等非必要功能。

3. 代码优化避免连续请求内存增长

  • 全局初始化核心资源:在Django的AppConfig中初始化全局的ClientSession和Semaphore,不要在每个视图或请求中重复创建:
    # apps.py
    from django.apps import AppConfig
    import aiohttp
    import asyncio
    
    class MyAppConfig(AppConfig):
        default_auto_field = 'django.db.models.BigAutoField'
        name = 'myapp'
        session = None
        semaphore = None
    
        def ready(self):
            self.semaphore = asyncio.Semaphore(20)
            self.session = aiohttp.ClientSession(
                connector=aiohttp.TCPConnector(
                    limit=100,
                    limit_per_host=20,
                    enable_cleanup_closed=True
                )
            )
    
  • 隔离Django上下文:异步任务中避免直接引用request对象或ORM实例,若需操作数据库,用sync_to_async封装并确保上下文被销毁:
    from django.utils.decorators import sync_to_async
    
    @sync_to_async
    def get_db_data():
        return list(MyModel.objects.all())
    
  • 控制并发数:用全局Semaphore限制并发请求数,避免同时创建过多任务导致内存暴涨:
    async def fetch_data(session, url, semaphore):
        async with semaphore:
            async with session.get(url) as resp:
                return await resp.json()
    
  • 及时清理临时数据:处理完批量请求后,清空存储结果的临时列表、字典;用生成器代替列表存储中间数据,减少内存占用。
  • 精准触发GC:在批量请求完全处理完成、所有资源释放后,再调用gc.collect(),不要频繁触发GC(会影响性能)。
  • 定位泄漏点:用tracemalloc跟踪内存分配,找到持续增长的对象类型:
    import tracemalloc
    
    tracemalloc.start()
    # 执行批量请求
    snapshot = tracemalloc.take_snapshot()
    top_stats = snapshot.statistics('lineno')
    for stat in top_stats[:10]:
        print(stat)
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 16:05:53