Skip to content
New issue

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

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

Already on GitHub? # 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?

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

No branches or pull requests

3 participants