Dan, What's your thread pool size?
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? Robert On Sat, Aug 16, 2025, 00:35 Robert Turner <rtur...@e-djuster.ca> 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 <d...@danielgschwartz.com> > 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 <n82...@gmail.com> >> Sent: Friday, August 15, 2025 11:39 PM >> To: Tomcat Users List <users@tomcat.apache.org> >> Subject: Re: [EXTERNAL EMAIL] How to access a REST service >> >> > On 2025 Aug 15, at 22:03, Daniel Schwartz <d...@danielgschwartz.com >> <mailto:d...@danielgschwartz.com>> 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 <n82...@gmail.com>)< >> https://godaddy1.cloud-protect.net/email-details/?k=k1&payload=53616c7465645f5f4a8adbed4b5cf7a587f5f4df537a8eaec1a2b42d4d58936018b1ed681a23d9919bf8332d2b6b61429feb03a72599510c1c3ab28d5aaddc506ec4d56aaa261fcb98bd9aad462cad1cc8e2c0a7c87426fd5ac7bd5b6e2701e483c6c0dabfa7863325d5e1cce43460a01fdb3123cef7a62998f33320b7ee6a504f58e005390e8ee17f0cc8754779156e61decfa830f679ecb7c1779d40b153b44dd3c8946f5c5040afad656b12d548292c93d680a4c9c588dd499f91f4d3fe02cd457cde8bab1d939f1dcbfe104966e4bccd617fa2cf6cf872584c675598f814ea3508244febcc34102818eff6415cdd >> > >> Learn More< >> https://godaddy1.cloud-protect.net/email-details/?k=k1&payload=53616c7465645f5f4a8adbed4b5cf7a587f5f4df537a8eaec1a2b42d4d58936018b1ed681a23d9919bf8332d2b6b61429feb03a72599510c1c3ab28d5aaddc506ec4d56aaa261fcb98bd9aad462cad1cc8e2c0a7c87426fd5ac7bd5b6e2701e483c6c0dabfa7863325d5e1cce43460a01fdb3123cef7a62998f33320b7ee6a504f58e005390e8ee17f0cc8754779156e61decfa830f679ecb7c1779d40b153b44dd3c8946f5c5040afad656b12d548292c93d680a4c9c588dd499f91f4d3fe02cd457cde8bab1d939f1dcbfe104966e4bccd617fa2cf6cf872584c675598f814ea3508244febcc34102818eff6415cdd >> > >> 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 <d...@danielgschwartz.com >> <mailto:d...@danielgschwartz.com>> 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 <ch...@christopherschultz.net<mailto: >> ch...@christopherschultz.net>> >> >> > Sent: Friday, August 15, 2025 1:07 PM >> >> > To: users@tomcat.apache.org<mailto:users@tomcat.apache.org> >> >> > 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 <ch...@christopherschultz.net<mailto: >> ch...@christopherschultz.net>> >> >> >> Sent: Friday, August 15, 2025 12:18 PM >> >> >> To: users@tomcat.apache.org<mailto:users@tomcat.apache.org> >> >> >> 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-3A8080_ >> >> >>> H >> >> >>> olidaysRESTJSON-2D1.0-2DSNAPSHOT_webresources_holidaysandevents_count >> >> >>> r >> >> >>> ies&d=DwICaQ&c=euGZstcaTDllvimEN8b7jXrwqOf-v5A_CdpgnVfiiMM&r=AbCalLxz >> >> >>> o >> >> >>> pgQUG9LLcXdB80OM-GtDfItX76RMxNYqz4&m=NKm1FUayvDzFHyhbqCI0JR32OpW1rfTe >> >> >>> d >> >> >>> HFkAoC_xT6Cjqt4-wsVFtYKPtR38vFY&s=4BYNb88ZN6WvyMyyZcR1FyT6Jg-qa4JSDa9 >> >> >>> 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.HolidaysRESTJSONResourc >> >> >>> 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: users-unsubscr...@tomcat.apache.org<mailto: >> users-unsubscr...@tomcat.apache.org> >> >> >> For additional commands, e-mail: users-h...@tomcat.apache.org<mailto: >> users-h...@tomcat.apache.org> >> >> >> >> >> >> >> >> >> --------------------------------------------------------------------- >> >> >> To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org<mailto: >> users-unsubscr...@tomcat.apache.org> >> >> >> For additional commands, e-mail: users-h...@tomcat.apache.org<mailto: >> users-h...@tomcat.apache.org> >> >> >> >> >> > >> >> > >> >> > --------------------------------------------------------------------- >> >> > To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org<mailto: >> users-unsubscr...@tomcat.apache.org> >> >> > For additional commands, e-mail: users-h...@tomcat.apache.org<mailto: >> users-h...@tomcat.apache.org> >> >> > >> >> > >> >> > --------------------------------------------------------------------- >> >> > To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org<mailto: >> users-unsubscr...@tomcat.apache.org> >> >> > For additional commands, e-mail: users-h...@tomcat.apache.org<mailto: >> users-h...@tomcat.apache.org> >> >> >> >> >> >> --------------------------------------------------------------------- >> >> To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org<mailto: >> users-unsubscr...@tomcat.apache.org> >> >> For additional commands, e-mail: users-h...@tomcat.apache.org<mailto: >> users-h...@tomcat.apache.org> >> >> >>