How mboset.isEmpty can cause a memory leak – use mboset.notExists instead
I have worked on lots of leaks where code has used the isEmpty() method because it has leaked database connections. This article demonstrates why the isEmpty method doesn't always leak the mboset and how to avoid the leak.
IBM have stated that the mboset.isEmpty() method can leak an MBOSet if the MBOSet contains multiple MBOs.
Figure 1 How isEmpty() works when used for an MBOSet with one row
Figure 2 How isEmpty() can cause an MBOSet leak when used with an MBOSet with multiple rows
This is a sample DB Connection watchdog warning with the stack trace showing the use of isEmpty().
[1/17/20 15:18:31:345 GMT] 000000ce SystemOut????O 17 Jan 2020 15:18:31:345 [INFO] [SITMXServer] [] BMXAA7084I - The database connection has been opened for: 491521 ms DbConnectionWatchDog:Db Connection reference id=300893 SPID=111
?????????????Create time:1579273819824
?????????????Create stack trace:
?????????????psdi.server.DbConnectionWatchDog$ConnectionData.<init>(DbConnectionWatchDog.java:60)
?????????????psdi.server.DbConnectionWatchDog.addConnection(DbConnectionWatchDog.java:252)
?????????????psdi.server.ConRef.notifyDBConnectionWatchDog(ConRef.java:243)
?????????????psdi.server.DBManager.getConnectionDetail(DBManager.java:1693)
?????????????psdi.server.DBManager.getConnection(DBManager.java:1460)
?????????????psdi.server.AppService.getDBConnection(AppService.java:572)
???????????????psdi.mbo.MboSet.getNextRecordData(MboSet.java:3282)
????????????????????psdi.mbo.MboSet.fetchMbosActual(MboSet.java:2941)
??????????????????????????psdi.mbo.MboSet.fetchMbos(MboSet.java:2898)
??????????????????????????psdi.mbo.MboSet.getMbo(MboSet.java:2114)
??????????????????????????psdi.mbo.MboSet.isEmpty(MboSet.java:4410)
?????????????psdi.app.rsconfig.RSConfigSet.setQueryDetails(RSConfigSet.java:1865)
?????????????psdi.app.rsconfig.RSConfigSet.setUpDefaults(RSConfigSet.java:2093)
?????????????psdi.webclient.controls.ResultSetPortlet.setUpDefaults(ResultSetPortlet.java:710)
?????????????com.ibm._jsp._resultsetportlet._jspService(_resultsetportlet.java:826)
Use mboset.notExists instead of mboset.isEmpty
The best solution is to use the mboset.notExists() method because this does not leak an MBOSet.
领英推荐
Figure 3 How notExists() avoids an MBOSet leak when used with an MBOSet with multiple rows
?Should a PMR be raised for every single isEmpty?
No unless there are large numbers of leaks for a that stack trace.
This blog series
This article is one of a series of articles to help system administrators understand the Maximo logs and the underlying architecture.
If you like this article then please share or like it.
Whilst I support the wider Maximo community and encourage the spread of knowledge, when republishing content from this blog please include the originating author along with the article or parts of.
If people do find parts of this blog coming up in blogs/newsletters/communications then please contact me directly. I’m happy to connect on LinkedIn to discuss.
Disclaimer
The postings on this blog are my own and don't necessarily represent Vetasi's positions, strategies or opinions.
The materials on this site are provided "AS IS" and the author will not be liable for any direct, indirect or incidental damages arising out or relating to any use or distribution of them. Readers are advised to test any changes/recommendations thoroughly before use
Technical Design Authority / IBM Champion for Cloud
2 年In my next artice I explain how setting an MBOSet to be discardable can help avoid memory leaks - https://www.dhirubhai.net/pulse/how-can-discardable-mboset-help-avoid-memory-leaks-mark-robbins/
Founder @ Sharptree
2 年The isEmpty() method essentially is evaluating "mboSet.getMbo(0) == null", so how does this cause a database leak? It is simply checking if there is a record in the set at index zero, which is a pretty common operation. Does calling "mboSet.getMbo(0)" to fetch a record also potentially create a leak? The notExist() method appears to be considerably more complex and actually gets a database connection from the DBConnection manager with the user's connection key, builds a select statement with many string concatenations to do a "select 1 from dummy_table where exists (select * from [current table and where clause here])" and then creates a JDBC Statement, and executes that statement to get a JDBC ResultSet and finally calls "next()" on the ResultSet object to move the cursor on the ResultSet and see if it has a record. All that to say, the notExist() seems to be far less performant and the fact that is going get a dedicated connection to explicitly re-execute the statement to determine if there is a record doubles the number of times that that query is going to be executed. Given that "notExists()" is not clearly a better option, what is the mechanism by which mboSet.getMbo(0) leaks connections?