Skip to content

fix: reduce memory overhead of .finalize() methods in PgConnection and StreamWrapper #2817

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

Merged
merged 1 commit into from
Feb 19, 2023

Conversation

vlsi
Copy link
Member

@vlsi vlsi commented Feb 18, 2023

Previously, an abandoned PgConnection could retain a significant amount of heap. Now the bare minimum is moved to a separate class, so the abandoned connections can be removed from the heap earlier.

This does not remove the use of .finalize(), and it only reduces the amount of retained heap memory.

@vlsi vlsi force-pushed the reduce_finalize_overhead branch 7 times, most recently from 8324a12 to 52d0762 Compare February 18, 2023 13:23
@vlsi vlsi force-pushed the reduce_finalize_overhead branch from 52d0762 to 1a12e09 Compare February 18, 2023 13:34
Comment on lines 64 to 78
// Prevent blocking the thread for too long
// The connection will be discarded anyway, so there's no much sense in waiting long
int timeout = pgStream.getNetworkTimeout();
if (timeout == 0 || timeout > 1000) {
pgStream.setNetworkTimeout(1000);
}
pgStream.sendChar('X');
pgStream.sendInteger4(4);

pgStream.flush();
pgStream.close();
Copy link
Member Author

Choose a reason for hiding this comment

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

Ideally, we should move this out of the finalizers thread, as it would get clogged if the application leaks more than one connection per second.
However, I would postpone that to a subsequent PR (e.g. move to PhantomReferences or something like that)

Copy link
Member

Choose a reason for hiding this comment

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

leaking more than 1 per second would only be a problem in face of networking issues causing us to hit the timeout, right?
In "happy path" of good connectivity to the database, sending the X4 should be much faster than that. Or am I missing something?

Copy link
Member Author

Choose a reason for hiding this comment

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

Imagine the user has something like:

for(i in 1..1000) {
  try {var con = openConnection();) {
    con.createStatement().execute(...);
  }
}
// assume the finalizer has not yet executed
// assume the firewall kills the connections, and it blocks any data for them

In that case, the finalizer thread would have a pile of 1000 connections to clean up, and it would take ~1000 seconds to unclog while all the other finalizers won't be able to process.

Of course, it is a rare case, however, the finalizer thread is shared across all the other finalizers, so in the ideal world, we should refrain from blocking it even for 1 second.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah - this is the horror scenario both in terms of volume of objects created, but also timing of network connectivity loss.

* Implementation note: it should keep only the minimum number of object references
* to reduce heap usage in case the user abandons connection without closing it first.
*/
public class QueryExecutorCloseAction implements Closeable {
Copy link
Member

Choose a reason for hiding this comment

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

does this need to be public?
could this be final?

Copy link
Member Author

Choose a reason for hiding this comment

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

Previously, QueryExecutorBase.sendCloseMessage was open, so I need to keep this class open

@vlsi vlsi force-pushed the reduce_finalize_overhead branch 2 times, most recently from cbdc97b to 18ba3f0 Compare February 18, 2023 15:45
@vlsi vlsi force-pushed the reduce_finalize_overhead branch 2 times, most recently from 8a0ff72 to 59739dd Compare February 18, 2023 19:17
@vlsi vlsi force-pushed the reduce_finalize_overhead branch 2 times, most recently from 78f159b to 5075513 Compare February 19, 2023 08:58
…d StreamWrapper

Previously, an abandoned PgConnection could retain a significant amount of heap.
Now the bare minimum is moved to a separate class, so the abandoned connections
can be removed from the heap earlier.

This does not remove the use of `.finalize()`, and it only reduces the amount of retained heap memory.

Fixes pgjdbc#1431
Fixes pgjdbc#1360
@vlsi vlsi force-pushed the reduce_finalize_overhead branch from 5075513 to ef370e8 Compare February 19, 2023 09:23
@vlsi vlsi merged commit c40855f into pgjdbc:master Feb 19, 2023
@embuc embuc mentioned this pull request Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants