Working through the numerous replies ...
-----Original Message-----
From: Robert Turner <[email protected]>
Sent: Saturday, August 16, 2025 1:03 AM
To: Tomcat Users List <[email protected]>
Subject: Re: [EXTERNAL EMAIL] How to access a REST service
Dan,
What's your thread pool size?
DGS: I don't know how to determine this.
With the default of 5, I can never get the high watermark for the connection
above 5 (as I would expect). If I bump up the thread pool max size, and
decrease the maximum db connection pool size, I can then get connections to
queue, etc.
They behave exactly as I would expect and I can never trigger a message about
being unable to obtain a connection.
I added a sleep of 200ms in the previous code I shared while holding the
connection to simulate being slow.
Everything worked without issue. I can fire thousands of connections at it with
no running out of connection problems. Requests queue up and wait for a
connection to be released.
There must be something wrong with how you are managing and using the
connections.
Could you provide a sample of the code that uses the connection?
DGS: Here is the current version of the code fragment that retrieves the list
of countries. The method call "GetCountryList.doIt(connection);" does create a
prepared statement, but this is always closed immediately after use. In any
case, the DB connection is always closed in the code below, as far as I can
tell. I've never seen an exception thrown in the running code, so I don't see
any possibility for a memory leak.
@Path("holidaysandevents")
public class HolidaysRESTJSONResource {
@Context
private UriInfo context;
DataSource dataSource;
public HolidaysRESTJSONResource() {
dataSource = DataSourceSingleton.getInstance().dataSource;
}
@GET
@Path("/countries")
@Produces(MediaType.APPLICATION_JSON)
public String getJsonCountries() {
if (TempDataStorage.countryList == null) {
Connection connection = null;
try {
connection = dataSource.getConnection();
TempDataStorage.countryList = GetCountryList.doIt(connection);
} catch (SQLException e) {
System.out.println(e.getStackTrace());
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException ex) {
System.out.println(ex.getStackTrace());
}
}
}
}
Robert
On Sat, Aug 16, 2025, 00:35 Robert Turner <[email protected]> wrote:
> Dan,
>
> FWIW, I just set up test Glassfish server, and made a trivial app to
> acquire and release a connection from the pool.
>
> I configured the connection with a minimum and starting size of 1.
>
> I tested with 1 connection, and it did exactly what I expected.
> Acquired and released 1 connection. No more connections were allocated.
>
> The setting for the minimum size is also the initial size (no
> surprise), and I could set that value to 1.
>
> My code to acquire the connection was this trivial code:
>
> final InitialContext ic = new InitialContext(); final DataSource ds =
> (DataSource) ic.lookup("test1"); try (Connection conn =
> ds.getConnection()) { } catch (SQLException e) {
> throw new Runtime exception(e);
> }
>
> So, I don't agree with your "conclusion" about 8 connections per.
>
> Robert
>
>
>
> On Sat, Aug 16, 2025, 00:02 Daniel Schwartz <[email protected]>
> wrote:
>
>> Chuck,
>>
>> Okay, here is the text of the attachment.
>>
>> Instance Name:
>> server
>>
>>
>>
>>
>> Resource : HolidaysConnectionPool Application :
>> HolidaysRESTJSON-1.0-SNAPSHOT
>>
>> Monitor (14 Statistics)
>> JDBC Connection Pool Statistics : HolidaysConnectionPool Name Value
>> Start Time Last Sample Time Details Description NumConnCreated
>> 8 count
>> Aug 15, 2025 1:26:20 AM
>> Aug 15, 2025 1:26:21 AM
>> --
>> The number of physical connections that were created since the last reset.
>> NumConnFree
>> 8count
>> Aug 15, 2025 1:26:20 AM
>> Aug 15, 2025 1:26:21 AM
>> High Water Mark: 8 count
>> Low Water Mark: 0 count
>> The total number of free connections in the pool as of the last sampling.
>> NumConnReleased
>> 1 count
>> Aug 15, 2025 1:26:20 AM
>> Aug 15, 2025 1:26:21 AM
>> --
>> Number of logical connections released to the pool.
>> NumPotentialConnLeak
>> 0 count
>> Aug 15, 2025 1:26:20 AM
>> --
>> --
>> Number of potential connection leaks
>> NumConnFailedValidation
>> 0 count
>> Aug 15, 2025 1:26:20 AM
>> --
>> --
>> The total number of connections in the connection pool that failed
>> validation from the start time until the last sample time.
>> ConnRequestWaitTime
>> 485millisecond
>> Aug 15, 2025 1:26:20 AM
>> Aug 15, 2025 1:26:21 AM
>> High Water Mark: 485 millisecond
>> Low Water Mark: 0 millisecond
>> The longest and shortest wait times of connection requests. The
>> current value indicates the wait time of the last request that was
>> serviced by the pool.
>> NumConnAcquired
>> 1 count
>> Aug 15, 2025 1:26:20 AM
>> Aug 15, 2025 1:26:21 AM
>> --
>> Number of logical connections acquired from the pool.
>> AverageConnWaitTime
>> 485 millisecond
>> Aug 15, 2025 1:26:20 AM
>> Aug 15, 2025 1:26:33 AM
>> --
>> Average wait-time-duration per successful connection request
>> NumConnDestroyed
>> 0 count
>> Aug 15, 2025 1:26:20 AM
>> --
>> --
>> Number of physical connections that were destroyed since the last reset.
>> NumConnSuccessfullyMatched
>> 0 count
>> Aug 15, 2025 1:26:20 AM
>> --
>> --
>> Number of connections succesfully matched
>> NumConnNotSuccessfullyMatched
>> 0 count
>> Aug 15, 2025 1:26:20 AM
>> --
>> --
>> Number of connections rejected during matching NumConnUsed 0count Aug
>> 15, 2025 1:26:20 AM Aug 15, 2025 1:26:21 AM High Water Mark: 1 count
>> Low Water Mark: 0 count Provides connection usage statistics. The
>> total number of connections that are currently being used, as well as
>> information about the maximum number of connections that were used
>> (the high water mark).
>> WaitQueueLength
>> 0 count
>> Aug 15, 2025 1:26:20 AM
>> --
>> --
>> Number of connection requests in the queue waiting to be serviced.
>> NumConnTimedOut
>> 0 count
>> Aug 15, 2025 1:26:20 AM
>> --
>> --
>> The total number of connections in the pool that timed out between
>> the start time and the last sample time.
>>
>> Regarding your statement "What is more likely is that the GlassFish
>> connection pool simply initializes the configured minimum number of
>> connections on the first attempt to acquire a connection.", I have no
>> idea hat this means.
>>
>> Dan
>>
>> From: Chuck Caldarale <[email protected]>
>> Sent: Friday, August 15, 2025 11:39 PM
>> To: Tomcat Users List <[email protected]>
>> Subject: Re: [EXTERNAL EMAIL] How to access a REST service
>>
>> > On 2025 Aug 15, at 22:03, Daniel Schwartz <[email protected]
>> <mailto:[email protected]>> wrote: > > I think I found the answer.
>> > > A few days ago, someone suggested that I try setting the
>> > > Glassfish
>> maximum pool size to 1 and see what happens.
>> NkdkJdXPPEBannerStart
>> Be Careful With This Message
>> From (Chuck Caldarale <[email protected]>)<
>> https://godaddy1.cloud-protect.net/email-details/?k=k1&payload=53616c
>> 7465645f5f4a8adbed4b5cf7a587f5f4df537a8eaec1a2b42d4d58936018b1ed681a2
>> 3d9919bf8332d2b6b61429feb03a72599510c1c3ab28d5aaddc506ec4d56aaa261fcb
>> 98bd9aad462cad1cc8e2c0a7c87426fd5ac7bd5b6e2701e483c6c0dabfa7863325d5e
>> 1cce43460a01fdb3123cef7a62998f33320b7ee6a504f58e005390e8ee17f0cc87547
>> 79156e61decfa830f679ecb7c1779d40b153b44dd3c8946f5c5040afad656b12d5482
>> 92c93d680a4c9c588dd499f91f4d3fe02cd457cde8bab1d939f1dcbfe104966e4bccd
>> 617fa2cf6cf872584c675598f814ea3508244febcc34102818eff6415cdd
>> >
>> Learn More<
>> https://godaddy1.cloud-protect.net/email-details/?k=k1&payload=53616c
>> 7465645f5f4a8adbed4b5cf7a587f5f4df537a8eaec1a2b42d4d58936018b1ed681a2
>> 3d9919bf8332d2b6b61429feb03a72599510c1c3ab28d5aaddc506ec4d56aaa261fcb
>> 98bd9aad462cad1cc8e2c0a7c87426fd5ac7bd5b6e2701e483c6c0dabfa7863325d5e
>> 1cce43460a01fdb3123cef7a62998f33320b7ee6a504f58e005390e8ee17f0cc87547
>> 79156e61decfa830f679ecb7c1779d40b153b44dd3c8946f5c5040afad656b12d5482
>> 92c93d680a4c9c588dd499f91f4d3fe02cd457cde8bab1d939f1dcbfe104966e4bccd
>> 617fa2cf6cf872584c675598f814ea3508244febcc34102818eff6415cdd
>> >
>> Potential Impersonation
>> The sender's identity could not be verified and someone may be
>> impersonating the sender. Take caution when interacting with this message.
>>
>> NkdkJdXPPEBannerEnd
>>
>>
>>
>> > On 2025 Aug 15, at 22:03, Daniel Schwartz <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>> >
>>
>> > I think I found the answer.
>>
>> >
>>
>> > A few days ago, someone suggested that I try setting the Glassfish
>> maximum pool size to 1 and see what happens. I reported back that in
>> Glassfish the minimum pool size is 8, to which someone responded that
>> this seems strange. I really didn't know. But now I do.
>>
>> >
>>
>> > Today I decided to run a test where I cleared out Glassfish so I
>> > could
>> start from scratch. I executed one REST request using the URL I
>> posted recently, which returns a list of countries. Then I looked at
>> the Glassfish JDBC pool monitor. A PDF of this is attached.
>>
>>
>>
>>
>>
>> The list strips nearly all attachments, for safely reasons. You need
>> to post the text.
>>
>>
>>
>>
>>
>> > You will see that it says the following:
>>
>> >
>>
>> > 1. NumConnAcquired, 1 count, Number of logical connection
>>
>> >
>>
>> > 2. NumConnReleased, 1 count, Number of logical connections released
>> > to
>> the pool.
>>
>> >
>>
>> > 3. NumConnCreated, 8 count, The number of physical connections that
>> were created since the last reset.
>>
>> >
>>
>> > 4. NumConnFree, 8count, The total number of free connections in the
>> pool as of the last sampling.
>>
>> >
>>
>> > I believe that this is why the minimum pool size is 8; each logical
>> connection requires 8 physical connections.
>>
>> >
>>
>> > This leads me to believe that this is why the number of connections
>> > in
>> my connection pool is much larger than what one would expect.
>> Assuming that Tomcat only requires one connection object per query,
>> this implies that Glassfish requires 8 times that amount.
>>
>>
>>
>>
>>
>> I think that is extremely unlikely. What is more likely is that the
>> GlassFish connection pool simply initializes the configured minimum
>> number of connections on the first attempt to acquire a connection.
>>
>>
>>
>> You can test this by making concurrent requests and seeing what
>> happens to the pool counters. Try inserting a delay in your code
>> between opening a connection and closing it; something like
>> Thread.currentThread().sleep(10000) would likely suffice. Then
>> initiate independent requests from several browser tabs in parallel;
>> the 10-second delay should allow time for each request to grab its
>> own connection from the pool while the other requests are still active.
>>
>>
>>
>>
>>
>> > So, while a normal pool size for Tomcat might be 20 connections, in
>> Glassfish this same activity would require 160 connections.
>>
>> >
>>
>> > In any case, I'm now 100% sure that my program doesn't, and never
>> > did,
>> have a memory leak. I have modified my code according to Chris's
>> recommendations, as this surely is good advice, but it hasn't changed
>> the performance, since no exceptions were ever being thrown.
>>
>>
>>
>>
>>
>> Did you apply the try-catch-finally pattern to all DB-related
>> objects, such as statements, prepared statements, and result sets?
>>
>>
>>
>> - Chuck
>>
>>
>>
>>
>>
>> > It appears to me that Glassfish is performing normally according to
>> > its
>> internal design, and there really is no problem as long as I keep the
>> maximum pool size large enough.
>>
>> >
>>
>> > What do you think?
>>
>> >
>>
>> > Dan
>>
>> >
>>
>> > -----Original Message-----
>>
>> > From: Christopher Schultz <[email protected]<mailto:
>> [email protected]>>
>>
>> > Sent: Friday, August 15, 2025 1:07 PM
>>
>> > To: [email protected]<mailto:[email protected]>
>>
>> > Subject: Re: [EXTERNAL EMAIL] How to access a REST service
>>
>> >
>>
>> > Dan,
>>
>> >
>>
>> > The only reason we are all looking for resource leaks (technically
>> > not
>> memory leaks, but leaks nonetheless) is because it's the best
>> explanation for why your connection pool seems to be running dry.
>>
>> >
>>
>> > I don't think that switching to Tomcat (or TomEE) is going to make
>> > any
>> difference.
>>
>> >
>>
>> > -chris
>>
>> >
>>
>> > On 8/15/25 12:33 PM, Daniel Schwartz wrote:
>>
>> >>
>>
>> >>
>>
>> >> -----Original Message-----
>>
>> >> From: Christopher Schultz <[email protected]<mailto:
>> [email protected]>>
>>
>> >> Sent: Friday, August 15, 2025 12:18 PM
>>
>> >> To: [email protected]<mailto:[email protected]>
>>
>> >> Subject: Re: [EXTERNAL EMAIL] How to access a REST service
>>
>> >>
>>
>> >> Daniel,
>>
>> >>
>>
>> >> On 8/15/25 12:49 AM, Daniel Schwartz wrote:
>>
>> >>> Robert (and all),
>>
>> >>>
>>
>> >>> I will work on answers your various questions. However, I
>> >>> decided to
>> first explore the comment (by someone) that a servlet can "swallow"
>> an exception, which I take to mean that it can throw an exception
>> without reporting the exception or terminating the program.
>>
>> >>>
>>
>> >>> I have this system running on a PC identified as localhost. The
>> >>> test
>> URL is:
>>
>> >>>
>>
>> >>> https://urldefense.proofpoint.com/v2/url?u=http-3A__localhost-3A8
>> >>> 080_
>>
>> >>> H
>>
>> >>> olidaysRESTJSON-2D1.0-2DSNAPSHOT_webresources_holidaysandevents_c
>> >>> ount
>>
>> >>> r
>>
>> >>> ies&d=DwICaQ&c=euGZstcaTDllvimEN8b7jXrwqOf-v5A_CdpgnVfiiMM&r=AbCa
>> >>> lLxz
>>
>> >>> o
>>
>> >>> pgQUG9LLcXdB80OM-GtDfItX76RMxNYqz4&m=NKm1FUayvDzFHyhbqCI0JR32OpW1
>> >>> rfTe
>>
>> >>> d
>>
>> >>> HFkAoC_xT6Cjqt4-wsVFtYKPtR38vFY&s=4BYNb88ZN6WvyMyyZcR1FyT6Jg-qa4J
>> >>> SDa9
>>
>> >>> P
>>
>> >>> xsSFgB4&e=
>>
>> >>>
>>
>> >>> I ran two tests. First, I wrote in code to throw an SQL
>> >>> exception,
>> which did get caught in my catch clause, which printed out some
>> messages and a stack trace. The web browser showed the retrieved
>> list of countries, but nothing else.
>>
>> >>>
>>
>> >>> Second, I replaced the line that throws the SQL exception by one
>> >>> that
>> tries to do a division by zero. This of course was not caught, but
>> it did print out a stack trace and reported a 505 error in the
>> browser, and the program did terminate.
>>
>> >>>
>>
>> >>> I take this to mean that exceptions are not being "swallowed" by
>> >>> my
>> program. When/if an exception occurs, there is definitely some
>> indication of this, either in the server.log or the browser. Because
>> I have never seen either of these actions, I'm fairly sure that my
>> program is not throwing exceptions and all database connections are
>> being closed immediately after they are used, i.e., no memory leaks in this
>> respect.
>>
>> >>>
>>
>> >>> The actual code fragments and outputs are copied below.
>>
>> >>>
>>
>> >>> ----------------------------------------------------------------
>>
>> >>> The code that throws the SQL exception
>>
>> >>> ----------------------------------------------------------------
>>
>> >>> @GET
>>
>> >>> @Path("/countries")
>>
>> >>> @Produces(MediaType.APPLICATION_JSON)
>>
>> >>> public String getJsonCountries() {
>>
>> >>> if (TempDataStorage.countryList == null) {
>>
>> >>> Connection connection = null;
>>
>> >>> try {
>>
>> >>> connection = dataSource.getConnection();
>>
>> >>> System.out.println("countries connection has
>> >>> been
>> opened");
>>
>> >>> TempDataStorage.countryList =
>> GetCountryList.doIt(connection);
>>
>> >>> throw new SQLException("testing sql exception");
>>
>> >>> // connection.close();
>>
>> >>> // System.out.println("countries connection has been
>> closed");
>>
>> >>> } catch (SQLException e) {
>>
>> >>> System.out.println(e);
>>
>> >>> System.out.println("catching sql exception");
>>
>> >>> if (connection != null) {
>>
>> >>> try {
>>
>> >>> connection.close();
>>
>> >>> } catch (SQLException ex) {
>>
>> >>> System.out.println(ex);
>>
>> >>> }
>>
>> >>> }
>>
>> >>> }
>>
>> >>> }
>>
>> >>
>>
>> >> 100% connection leak every time, guaranteed.
>>
>> >>
>>
>> >> You are never closing the connection, because it's been commented out.
>>
>> >> Perhaps this was just for testing, because I see you are throwing
>> >> an
>> exception.
>>
>> >>
>>
>> >> DGS: When I put in the throw statement, I had to comment out those
>> >> two
>> lines because the Java compiler complains that they are unreachable.
>> This was just to test for what would happen if an SQL exception was
>> thrown, in which case, yes, there will be a memory. The point is
>> that my program never throws SQL exceptions, because if it did, I would know
>> about it.
>>
>> >>
>>
>> >> The conn.close() *MUST* be in a finally {} block. Do not put it in
>> >> the
>> try block. Do not put it in the catch block. Always put it in the
>> finally block.
>>
>> >>
>>
>> >> DGS: Sounds like good advice. I'll do this and see if it makes a
>> difference.
>>
>> >>
>>
>> >>> -----------------------------------------------------------------
>> >>> -
>>
>> >>> The output in the server.log file
>>
>> >>> -----------------------------------------------------------------
>> >>> -
>>
>> >>> [2025-08-14T23:34:42.019-0400] [glassfish 4.1] [INFO] [] [] [tid:
>> _ThreadID=40 _ThreadName=Thread-8] [timeMillis: 1755228882019] [levelValue:
>> 800] [[
>>
>> >>> countries connection has been opened]]
>>
>> >>>
>>
>> >>> [2025-08-14T23:34:42.022-0400] [glassfish 4.1] [INFO] [] [] [tid:
>> _ThreadID=40 _ThreadName=Thread-8] [timeMillis: 1755228882022] [levelValue:
>> 800] [[
>>
>> >>> java.sql.SQLException: testing sql exception
>>
>> >>> at
>>
>> >>> com.worldholidaysandevents.restjsonwebservice.HolidaysRESTJSONRes
>> >>> ourc
>>
>> >>> e
>>
>> >>> .getJsonCountries(HolidaysRESTJSONResource.java:54)
>>
>> >>>
>>
>> >>> ... stack trace ...
>>
>> >>>
>>
>> >>> [2025-08-14T23:34:42.022-0400] [glassfish 4.1] [INFO] [] [] [tid:
>> _ThreadID=40 _ThreadName=Thread-8] [timeMillis: 1755228882022] [levelValue:
>> 800] [[
>>
>> >>> catching sql exception]]
>>
>> >>
>>
>> >> ... and the server does not crash. You can make any request
>> >> without
>> restarting Glassfish, right?
>>
>> >>
>>
>> >>> ----------------------------------------------------------------
>>
>> >>> The code that divides by zero
>>
>> >>> ----------------------------------------------------------------
>>
>> >>> @GET
>>
>> >>> @Path("/countries")
>>
>> >>> @Produces(MediaType.APPLICATION_JSON)
>>
>> >>> public String getJsonCountries() {
>>
>> >>> if (TempDataStorage.countryList == null) {
>>
>> >>> Connection connection = null;
>>
>> >>> try {
>>
>> >>> connection = dataSource.getConnection();
>>
>> >>> System.out.println("countries connection has
>> >>> been
>> opened");
>>
>> >>> TempDataStorage.countryList =
>> GetCountryList.doIt(connection);
>>
>> >>> float something = 1/0;
>>
>> >>> connection.close();
>>
>> >>> System.out.println("countries connection has
>> >>> been
>> closed");
>>
>> >>> } catch (SQLException e) {
>>
>> >>> System.out.println(e);
>>
>> >>> System.out.println("catching sql exception");
>>
>> >>> if (connection != null) {
>>
>> >>> try {
>>
>> >>> connection.close();
>>
>> >>> } catch (SQLException ex) {
>>
>> >>> System.out.println(ex);
>>
>> >>> }
>>
>> >>> }
>>
>> >>> }
>>
>> >>> }
>>
>> >>
>>
>> >>
>>
>> >> 100% connection leak every time, guaranteed.
>>
>> >>
>>
>> >> You are never closing the connection, because your code is
>> >> throwing an
>> uncaught exception (divide by zero) Perhaps this was just for
>> testing, because I see you are intentionally dividing by zero.
>>
>> >>
>>
>> >> DGS: Right. This was to test for what would happen if a non-SQL
>> exception were thrown, i.e., one that is not caught in the catch clause.
>> This created a 505 error and the program quit running. Here the
>> point is that, if something like this were to happen, I would
>> certainly know about it, and it has never happened, so no memory leak
>> is being created in this way.
>>
>> >>
>>
>> >> The conn.close() *MUST* be in a finally {} block. Do not put it in
>> >> the
>> try block. Do not put it in the catch block. Always put it in the
>> finally block.
>>
>> >>
>>
>> >> DGS: Thanks again. I'll do this and see if it makes any
>> >> difference in
>> the connection pooling.
>>
>> >>
>>
>> >> -chris
>>
>> >>
>>
>> >>
>>
>> >> ------------------------------------------------------------------
>> >> ---
>>
>> >> To unsubscribe, e-mail: [email protected]<mailto:
>> [email protected]>
>>
>> >> For additional commands, e-mail: [email protected]<mailto:
>> [email protected]>
>>
>> >>
>>
>> >>
>>
>> >> ------------------------------------------------------------------
>> >> ---
>>
>> >> To unsubscribe, e-mail: [email protected]<mailto:
>> [email protected]>
>>
>> >> For additional commands, e-mail: [email protected]<mailto:
>> [email protected]>
>>
>> >>
>>
>> >
>>
>> >
>>
>> > -------------------------------------------------------------------
>> > --
>>
>> > To unsubscribe, e-mail: [email protected]<mailto:
>> [email protected]>
>>
>> > For additional commands, e-mail: [email protected]<mailto:
>> [email protected]>
>>
>> >
>>
>> >
>>
>> > -------------------------------------------------------------------
>> > --
>>
>> > To unsubscribe, e-mail: [email protected]<mailto:
>> [email protected]>
>>
>> > For additional commands, e-mail: [email protected]<mailto:
>> [email protected]>
>>
>>
>>
>>
>>
>> ---------------------------------------------------------------------
>>
>> To unsubscribe, e-mail: [email protected]<mailto:
>> [email protected]>
>>
>> For additional commands, e-mail: [email protected]<mailto:
>> [email protected]>
>>
>>
>>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]