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

pgx.Conn: Fix memory leak: Delete items from preparedStatements #1614

Merged
merged 1 commit into from
May 20, 2023
Merged

pgx.Conn: Fix memory leak: Delete items from preparedStatements #1614

merged 1 commit into from
May 20, 2023

Conversation

evanj
Copy link
Contributor

@evanj evanj commented May 17, 2023

Previously, items were never removed from the preparedStatements map. This means workloads that send a large number of unique queries could run out of memory. Delete items from the map when sending the deallocate command to Postgres. Add a test to verify this works.

Fixes #1456

@evanj
Copy link
Contributor Author

evanj commented May 17, 2023

I could not find a way to test this using the public interface, so I wrote a test that directly inspects the internals of this type. I guess the alternative might be to check the amount of memory being used? This seemed like the easiest way to do this to me, but I would be happy to take better ideas!

Previously, items were never removed from the preparedStatements map.
This means workloads that send a large number of unique queries could
run out of memory. Delete items from the map when sending the
deallocate command to Postgres. Add a test to verify this works.

Fixes #1456
@evanj evanj changed the title pgx.Conn: Delete items from preparedStatements map after Deallocate pgx.Conn: Fix memory leak: Delete items from preparedStatements May 17, 2023
@jackc jackc merged commit 0292ede into jackc:master May 20, 2023
@jackc
Copy link
Owner

jackc commented May 20, 2023

LGTM - good catch and fix!

@@ -1326,6 +1326,7 @@ func (c *Conn) deallocateInvalidatedCachedStatements(ctx context.Context) error

for _, sd := range invalidatedStatements {
pipeline.SendDeallocate(sd.Name)
delete(c.preparedStatements, sd.Name)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this actually might not solve the "leak" issue, since Go won't deallocate memory after you delete a key from a map golang/go#20135

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The map itself won't shrink, but delete() does zero the keys and values in the map, so the *pgconn.StatementDescription value will be garbage collected. Additionally, delete() decrements the size of the map, which means its capacity will now be limited to the max number of prepared statements (with extra space for the map "fill factor"). This means this change should mean the amount of memory used by the c.preparedStatements is now fixed, rather than increasing without bound.

Additionally, my reproduction program on the original issue can run forever without running out of memory: #1456 (comment)

So: I'm pretty confident that this fix will resolve this specific bug at least. There could be others though! I would be happy to try to figure them out if we have a sample program that reproduces the problem.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete() does zero the keys and values in the map

yes, only if they poiners

Additionally, delete() decrements the size of the map

I can be wrong, but regarding this example the allocated size of the map would be the same.

which means its capacity will now be limited to the max number of prepared statements

well I guess it's true if the pgx has limitations to prepared statement cache

@evanj evanj deleted the fix-conn-prepared-statements-leak branch June 8, 2023 12:52
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

Successfully merging this pull request may close these issues.

Possible memory leak?
3 participants