All posts

Fix Memory Leak in Flask

Find and fix memory leaks in Flask applications caused by global state, unclosed database connections, and large response buffering.

Memory Leaks in Flask

Flask's simplicity can mask memory leaks that grow with each request. Since Flask often runs in long-lived worker processes under Gunicorn, these leaks accumulate until the OOM killer intervenes.

Global State Accumulation

Storing data in module-level variables that grow per request:

# BAD — grows forever
request_log = []

@app.route('/api/data')
def get_data():
    request_log.append(request.args)  # Never cleared
    return jsonify(data)

Use Redis or a proper logging system instead.

Unclosed Database Connections

# BAD — connection never returned to pool
@app.route('/users')
def users():
    conn = engine.connect()
    result = conn.execute(text('SELECT * FROM users'))
    return jsonify([dict(r) for r in result])
    # conn.close() never called

# GOOD — use context manager
@app.route('/users')
def users():
    with engine.connect() as conn:
        result = conn.execute(text('SELECT * FROM users'))
        return jsonify([dict(r) for r in result])

Large Response Buffering

Streaming large files instead of loading them into memory:

# BAD — reads entire file into memory
@app.route('/download')
def download():
    data = open('large_file.csv').read()
    return data

# GOOD — stream it
@app.route('/download')
def download():
    def generate():
        with open('large_file.csv') as f:
            for line in f:
                yield line
    return Response(generate(), mimetype='text/csv')

Gunicorn Worker Recycling

As a safety net, restart workers after a number of requests:

# gunicorn.conf.py
max_requests = 1000
max_requests_jitter = 50

Bugsly tracks per-worker memory usage in Flask apps, alerting when a specific worker is growing disproportionately.

Try Bugsly Free

AI-powered error tracking that explains your bugs. Set up in 2 minutes, free forever for small projects.

Get Started Free