Subject: [pgjdbc/pgjdbc] issue #3902: createBlob() not closing LargeObject.

From: "batman007db (@batman007db)" <[email-masked]>
Date: Wed, 31 Dec 2025 10:28:55 +0000

**Describe the issue**
So the "setBlob()" method consumes some direct memory but then doesnt release it? Asking this because the "setBlob()" internally calls "createBlob()" and in it a "LargeObject" is created and  opened (through "open()) but then not closed? So i think that LargeObject is not closed.

**Driver Version?** 
42.7.3

---

From: "davecramer (@davecramer)" <[email-masked]>
Date: Wed, 31 Dec 2025 12:08:52 +0000

OutputStreams are closable so in the try with resources it will be closed

https://github.com/pgjdbc/pgjdbc/blob/e3ea9a3bfce6330aea67b3ff555cd7c32a755134/pgjdbc/src/main/java/org/postgresql/jdbc/PgPreparedStatement.java#L1259-L1278

---

From: "batman007db (@batman007db)" <[email-masked]>
Date: Thu, 01 Jan 2026 07:40:43 +0000

Cool. but when i tried java profiling in jconsole, the direct memory increases by a specific amount when ```setBlob()``` was called and then that memory wasnt getting released. Is there anything that I am missing? like after how long is the direct memory released or something else?. If needed i can provided the jconsole's  direct memory graph usage from my application.

---

From: "davecramer (@davecramer)" <[email-masked]>
Date: Thu, 01 Jan 2026 11:34:42 +0000

Can you share the profile information?

---

From: "davecramer (@davecramer)" <[email-masked]>
Date: Fri, 02 Jan 2026 14:15:15 +0000

So there's a point where we probably leave the blob outputstream open due to an infinite loop. The best we can do is set it to null and wait for the GC to recover the memory
https://github.com/pgjdbc/pgjdbc/blob/e3ea9a3bfce6330aea67b3ff555cd7c32a755134/pgjdbc/src/main/java/org/postgresql/largeobject/LargeObject.java#L162-L174

---

From: "vlsi (@vlsi)" <[email-masked]>
Date: Fri, 02 Jan 2026 20:19:59 +0000

@batman007db , it would be great if you could share the profiling you have.

If you can reproduce the behavior with a simpler example, it would help as well.

---

> profiling in jconsole, the direct memory increases

As far as I understand, it should not be connected with pgjdbc. I do not think pgjdbc uses direct memory at the moment.

---

You could use https://github.com/async-profiler/async-profiler to profile nativememory via `event=nativemem`. See https://github.com/async-profiler/async-profiler/blob/master/docs/ProfilerOptions.md

---

Here we should use try-with-resources for `LargeObject` as well: https://github.com/pgjdbc/pgjdbc/blob/62c9805ef8606f3d38273ac69f64b14e936a0bfa/pgjdbc/src/main/java/org/postgresql/jdbc/PgPreparedStatement.java#L1258

I think the intention was "ok, we intend to use the blob as prepared statement sometime later.
However, in practice closing the lob (calling `lo_close` API) does not invalidate large object oid, and it just releases a server-side handle.
I guess we should better close the handle anyway as we do not access the lob after we create and populate it.

However, I do not think it would impact "direct memory increases".

---

@batman007db , it would be great if you could try moving `LargeObject` into try as follows (I have not tried it yet, however, it looks safe):

```java
    try (LargeObject lob = lom.open(oid);
         OutputStream outputStream = lob.getOutputStream()) {
```

However, I do not think it would impact your case though.