Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Potential memory leak when accessing the Diagnostics attribute of an IntegrityError #557

Open
davidcoffin opened this issue May 23, 2017 · 2 comments

Comments

@davidcoffin
Copy link

We recently had a memory leak on one of our servers and it stopped as soon as we commented out the line of code assigning the Diagnostics attribute of an IntegrityError to a local variable within the exception handler.

The code below replicates the issue for Python 3.5.2, Psycopg 2.6.1. When I run this the amount of resident memory used by the process steadily increases, although not every time func() is called.

#!/usr/bin/env python3

import psycopg2
import itertools
import gc
import os

conn = psycopg2.connect(os.getenv('DSN'))

def main():
    with conn:
        with conn.cursor() as cur:
            cur.execute('CREATE TABLE IF NOT EXISTS leaky (id integer UNIQUE)')

    for n in itertools.count(1):
        print(n, resident_memory_usage())
        func()

def func():
    with conn:
        with conn.cursor() as cur:
            try:
                cur.execute("INSERT INTO leaky VALUES (1)")
            except psycopg2.IntegrityError as e:
                diag = e.diag # this assignment results in a memory leak unless it's explicitly deleted
                #e.diag # just accessing the attribute does not result in a memory leak
    #del diag # explicitly deleting stops the leak
    #gc.collect() # <-- garbage collecting doesn't help even though the only reference should be circular

def resident_memory_usage():
    with open('/proc/self/status') as status:
        for line in status:
            parts = line.split()
            if parts[0][2:-1].lower() == 'rss':
                return int(parts[1])

if __name__ == '__main__':
    main()
dvarrazzo added a commit that referenced this issue May 23, 2017
Triyng to fix a reported memory leak with diags, but implementing
traversing doesn't help. Quite the opposite in the example provided in
bug #557, the leak is present even with the `del diag`.

The leak appears with Python 3.5, not with Python 2.7.
@dvarrazzo
Copy link
Member

Thank you for the report and the script to reproduce, @davidcoffin !

I've played a bit with it... only to make it worse: implementing object traversal in the Diagnostics object makes only sure that the leak stays there even with the del diag :\

I'll look further into it...

@dvarrazzo dvarrazzo added this to the psycopg 2.7.2 milestone Jun 8, 2017
@dvarrazzo dvarrazzo removed this from the psycopg 2.7.2 milestone Nov 13, 2017
@GuardianRain
Copy link

What is the latest progress?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants