Skip to content

Commit ebd1ceb

Browse files
guizmaiistaticlibs
authored andcommitted
Remove finalize() methods (1.5)
This is a backport of the PR duckdb#533 to `v1.5-variegata` stable branch. Problem ------- In highly parallel environments, creating DuckDBResultSet and DuckDBPreparedStatement objects causes severe mutex contention on the global java.lang.ref.Finalizer lock. Profiling with Pyroscope showed that ~48% of mutex contentions originated from: DuckDBResultSet.<init> → Object.<init> → Finalizer.register → Finalizer.<init> [GLOBAL LOCK] When a class overrides finalize(), the JVM registers every new instance with the Finalizer system using a global lock. In applications executing many concurrent queries (e.g., using ZIO, Akka, or thread pools), this single lock becomes a severe bottleneck, significantly degrading throughput. Background ---------- The finalize() methods were added in April 2020 (commit 934af9f) as a safety net to release native JNI resources if users forgot to call close(). However, finalize() was deprecated in Java 9 (2017) due to: - Unpredictable execution timing (GC-dependent) - Performance overhead (extra GC cycles for weak reachability) - Global lock contention in the Finalizer registration - Single-threaded Finalizer thread becoming a bottleneck The modern replacement (java.lang.ref.Cleaner) was introduced in Java 9, but this driver targets Java 8 compatibility. Solution -------- Remove finalize() from all four classes that had it: - DuckDBConnection - DuckDBPreparedStatement - DuckDBResultSet - DuckDBSingleValueAppender All these classes already implement AutoCloseable with proper close() methods. Users should use try-with-resources: try (Connection conn = DriverManager.getConnection("jdbc:duckdb:"); PreparedStatement stmt = conn.prepareStatement(sql); ResultSet rs = stmt.executeQuery()) { // ... } This is standard JDBC best practice and ensures deterministic resource cleanup without relying on GC finalization. Impact ------ - Eliminates Finalizer lock contention entirely - Improves throughput in high-concurrency scenarios - No behavior change for users who properly close resources - Users who relied on finalize() for cleanup will now leak resources if they don't call close() (but finalize() was never guaranteed to run anyway)
1 parent 4a6fab8 commit ebd1ceb

4 files changed

Lines changed: 0 additions & 23 deletions

File tree

src/main/java/org/duckdb/DuckDBConnection.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,6 @@ public void rollback() throws SQLException {
122122
}
123123
}
124124

125-
@Override
126-
@SuppressWarnings("deprecation")
127-
protected void finalize() throws Throwable {
128-
close();
129-
}
130-
131125
public void close() throws SQLException {
132126
if (isClosed()) {
133127
return;

src/main/java/org/duckdb/DuckDBPreparedStatement.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -411,12 +411,6 @@ public boolean isClosed() throws SQLException {
411411
return conn == null || conn.connRef == null;
412412
}
413413

414-
@Override
415-
@SuppressWarnings("deprecation")
416-
protected void finalize() throws Throwable {
417-
close();
418-
}
419-
420414
@Override
421415
public int getMaxFieldSize() throws SQLException {
422416
checkOpen();

src/main/java/org/duckdb/DuckDBResultSet.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,6 @@ public void close() throws SQLException {
110110
}
111111
}
112112

113-
@Override
114-
@SuppressWarnings("deprecation")
115-
protected void finalize() throws Throwable {
116-
close();
117-
}
118-
119113
public boolean isClosed() throws SQLException {
120114
return resultRef == null;
121115
}

src/main/java/org/duckdb/DuckDBSingleValueAppender.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,6 @@ public void append(byte[] value) throws SQLException {
9393
}
9494
}
9595

96-
@SuppressWarnings("deprecation")
97-
protected void finalize() throws Throwable {
98-
close();
99-
}
100-
10196
public synchronized void close() throws SQLException {
10297
if (appender_ref != null) {
10398
DuckDBNative.duckdb_jdbc_appender_close(appender_ref);

0 commit comments

Comments
 (0)