Re: JDBC PreparedStatement Memory Leak. - Mailing list pgsql-patches

From Barry Lind
Subject Re: JDBC PreparedStatement Memory Leak.
Date
Msg-id 3CA0B34E.7000806@xythos.com
Whole thread Raw
In response to Re: JDBC PreparedStatement Memory Leak.  (Bruce Momjian <pgman@candle.pha.pa.us>)
Responses Re: JDBC PreparedStatement Memory Leak.
List pgsql-patches
Leif,

In looking at this patch, I don't understand the bug that it is trying
to fix.  I looked over how the ThreadLocal objects are being used in the
code and don't see how they could cause a memory leak.  Can you explain
where the bug exists in the current logic?  Or alternatively can you
provide a test case that demonstrates the problem so that I can look
into it some more here.

Also when submitting patches, please send them in diff -c format.

thanks,
--Barry


Bruce Momjian wrote:
> Can you send a context diff, diff -c?  Thanks.
>
> ---------------------------------------------------------------------------
>
> Leif Mortenson wrote:
>
>>I encountered a very large memory leak when using PreparedStatements in
>>a Java Application.
>>
>>The memory leak only shows itself where all of the following are true:
>>1) The Threads which use the PreparedStatements have a long lifetime.
>>2) setDate() or setTimestamp is called on the PreparedStatements.
>>3) The PreparedStatements are being used enough to notice the leak.
>>
>>In my application, my JVM was running out of memory around 330MB after
>>about 1 hour of
>>continuous opertion. I was able to find the problem by using the Java
>>Profiler. It showed
>>that around 100,000 instances of SimpleDateFormat and their subobjects
>>were hanging around
>>in memory.
>>
>>It turns out that this was being caused by the way PreparedStatement was
>>using
>>ThreadLocal instances. Each one was creating a SimpleDateFormat which
>>via the
>>ThreadLocal gets set into a HashMap in the current Thread. These never
>>get cleaned
>>up until the Thread itself is GCed.
>>
>>It looks like this had been discovered last summer and there were some
>>posts about a
>>patch having been committed. But the problem is still there.
>>
>>Here is the patch that I made to fix this.
>>
>>Cheers,
>>Leif
>>
>>RCS file:
>>/projects/cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java,v
>>retrieving revision 1.24
>>diff -w -r1.24 PreparedStatement.java
>>42,45c42,45
>>< // We use ThreadLocal for SimpleDateFormat's because they are not that
>>< // thread safe, so each calling thread has its own object.
>>< private static ThreadLocal tl_df = new ThreadLocal(); // setDate()
>>SimpleDateFormat
>>< private static ThreadLocal tl_tsdf = new ThreadLocal(); //
>>setTimestamp() SimpleDateFormat
>>---
>>
>>>// Store a copy of SimpleDataFormats for each instance and synchronize
>>
>>them as they
>>
>>>// are not very thread safe.
>>>private static SimpleDateFormat df; // setDate() SimpleDateFormat
>>>private static SimpleDateFormat tsdf; // setTimestamp() SimpleDateFormat
>>
>>351c351
>>< SimpleDateFormat df = (SimpleDateFormat) tl_df.get();
>>---
>>
>>>SimpleDateFormat df = this.df;
>>
>>354,355c354,356
>>< df = new SimpleDateFormat("''yyyy-MM-dd''");
>>< tl_df.set(df);
>>---
>>
>>>// It is possible that two threads could get in here, but it
>>>// does not cause problems.
>>>this.df = df = new SimpleDateFormat("''yyyy-MM-dd''");
>>
>>357c358,365
>>< set(parameterIndex, df.format(x));
>>---
>>
>>>String formatX;
>>>synchronized(df)
>>>{
>>>// SimpleDateFormats are not thread safe.
>>>formatX = df.format(x);
>>>}
>>>set(parameterIndex, formatX);
>>
>>407c415
>>< SimpleDateFormat df = (SimpleDateFormat) tl_tsdf.get();
>>---
>>
>>>SimpleDateFormat df = tsdf;
>>
>>409a418,419
>>
>>>// It is possible that two threads could get in here, but it
>>>// does not cause problems.
>>
>>412c422
>>< tl_tsdf.set(df);
>>---
>>
>>>tsdf = df;
>>
>>424a435,441
>>
>>>String formatX;
>>>synchronized(df)
>>>{
>>>// SimpleDateFormats are not thread safe.
>>>formatX = df.format(x);
>>>}
>>>
>>
>>429c446
>><
>>sbuf.append("'").append(df.format(x)).append('.').append(decimal).append("+00'");
>>---
>>
>>sbuf.append("'").append(formatX).append('.').append(decimal).append("+00'");
>>
>>
>>
>>
>>---------------------------(end of broadcast)---------------------------
>>TIP 5: Have you checked our extensive FAQ?
>>
>>http://www.postgresql.org/users-lounge/docs/faq.html
>>
>
>



pgsql-patches by date:

Previous
From: Ian Barwick
Date:
Subject: Re: psql slash command '\G'
Next
From: Barry Lind
Date:
Subject: Re: little error messages fix