Skip to content

Commit 78ee3f9

Browse files
committed
Bug fix: #1530 Memory leak: SQL result tabs were not garbage collect as long as their Session was open.
Note: When a result tab of an open Session gets garbage collected the following line appears is SQuirreL's logs: ...INFO ... Result tab finalized for open Session "<...>" with id=<...>
1 parent d15b267 commit 78ee3f9

File tree

8 files changed

+115
-39
lines changed

8 files changed

+115
-39
lines changed

sql12/core/doc/changes.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ Table cell data popup now offers find, Xml/Json-reformatting and export function
7474

7575
Bug fixes:
7676

77+
#1530 Memory leak: SQL result tabs were not garbage collect as long as their Session was open.
78+
Note: When a result tab of an open Session gets garbage collected the following line appears is SQuirreL's logs:
79+
...INFO ... Result tab finalized for open Session "<...>" with id=<...>
80+
7781
#1531 MySQL Plugin: SMALLINT UNSIGNED columns showed <Error> when the fields value exceeded 32767.
7882
Note: To work with MYSQL's SMALLINT UNSIGNED or TINYINT UNSIGNED types the MySQL Plugin must be installed.
7983

sql12/core/src/net/sourceforge/squirrel_sql/client/session/mainpanel/IResultTab.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@
1818
*/
1919
package net.sourceforge.squirrel_sql.client.session.mainpanel;
2020

21-
import java.awt.Window;
22-
import java.awt.event.ActionEvent;
23-
import javax.swing.JComponent;
24-
import javax.swing.JTabbedPane;
25-
2621
import net.sourceforge.squirrel_sql.fw.datasetviewer.IDataSetViewer;
2722
import net.sourceforge.squirrel_sql.fw.datasetviewer.TableState;
2823
import net.sourceforge.squirrel_sql.fw.datasetviewer.coloring.markduplicates.MarkDuplicatesChooserController;
2924
import net.sourceforge.squirrel_sql.fw.datasetviewer.columndisplaychoice.ResultDataSetAndCellDetailDisplayHandler;
3025
import net.sourceforge.squirrel_sql.fw.id.IntegerIdentifier;
3126

27+
import javax.swing.JComponent;
28+
import javax.swing.JTabbedPane;
29+
import java.awt.Window;
30+
import java.awt.event.ActionEvent;
31+
3232
public interface IResultTab
3333
{
3434
/**
@@ -49,6 +49,8 @@ public interface IResultTab
4949

5050
void disposeTab();
5151

52+
void addResultTabCloseListener(ResultTabCloseListener l);
53+
5254
void returnToTabbedPane();
5355

5456
/**

sql12/core/src/net/sourceforge/squirrel_sql/client/session/mainpanel/ResultTab.java

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,6 @@
2323
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2424
*/
2525

26-
import java.awt.BorderLayout;
27-
import java.awt.GridBagConstraints;
28-
import java.awt.GridBagLayout;
29-
import java.awt.Insets;
30-
import java.awt.Window;
31-
import java.awt.event.ActionEvent;
32-
import java.beans.PropertyChangeEvent;
33-
import java.beans.PropertyChangeListener;
34-
import javax.swing.JComponent;
35-
import javax.swing.JOptionPane;
36-
import javax.swing.JPanel;
37-
import javax.swing.JTabbedPane;
38-
import javax.swing.SwingUtilities;
39-
4026
import net.sourceforge.squirrel_sql.client.gui.builders.UIFactory;
4127
import net.sourceforge.squirrel_sql.client.session.DataModelImplementationDetails;
4228
import net.sourceforge.squirrel_sql.client.session.EditableSqlCheck;
@@ -77,6 +63,22 @@
7763
import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
7864
import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
7965

66+
import javax.swing.JComponent;
67+
import javax.swing.JOptionPane;
68+
import javax.swing.JPanel;
69+
import javax.swing.JTabbedPane;
70+
import javax.swing.SwingUtilities;
71+
import java.awt.BorderLayout;
72+
import java.awt.GridBagConstraints;
73+
import java.awt.GridBagLayout;
74+
import java.awt.Insets;
75+
import java.awt.Window;
76+
import java.awt.event.ActionEvent;
77+
import java.beans.PropertyChangeEvent;
78+
import java.beans.PropertyChangeListener;
79+
import java.util.ArrayList;
80+
import java.util.List;
81+
8082
public class ResultTab extends JPanel implements IHasIdentifier, IResultTab
8183
{
8284
private static final StringManager s_stringMgr = StringManagerFactory.getStringManager(ResultTab.class);
@@ -133,6 +135,8 @@ public class ResultTab extends JPanel implements IHasIdentifier, IResultTab
133135
private MarkDuplicatesChooserController _markDuplicatesChooserController;
134136
private ShowCellDetailCtrl _showCellDetailCtrl;
135137

138+
private List<ResultTabCloseListener> _resultTabCloseListenerList = new ArrayList<>();
139+
136140
/**
137141
* Ctor.
138142
*
@@ -376,6 +380,16 @@ public String getViewableSqlString()
376380
return StringUtilities.cleanString(getOriginalSqlString());
377381
}
378382

383+
/**
384+
* No need to remove this Listener, Closing the ResultTab will clear the listener list.
385+
*/
386+
@Override
387+
public void addResultTabCloseListener(ResultTabCloseListener l)
388+
{
389+
_resultTabCloseListenerList.remove(l);
390+
_resultTabCloseListenerList.add(l);
391+
}
392+
379393
public void disposeTab()
380394
{
381395
if (_metaDataDataSetViewerFindHandler != null)
@@ -390,6 +404,17 @@ public void disposeTab()
390404
_currentSqlLblCtrl.clear();
391405
_sql = "";
392406

407+
for( ResultTabCloseListener l : _resultTabCloseListenerList.toArray(new ResultTabCloseListener[0]) )
408+
{
409+
l.resultTabClosed();
410+
}
411+
_resultTabCloseListenerList.clear();
412+
413+
if(null != _resultDataSetViewerFindHandler && null != _resultDataSetViewerFindHandler.getDataSetViewer())
414+
{
415+
_resultDataSetViewerFindHandler.getDataSetViewer().setContinueReadChannel(null);
416+
}
417+
393418
_rsds.closeStatementAndResultSet();
394419
}
395420

@@ -757,4 +782,13 @@ public void selectSQLResultTabSelected()
757782
{
758783
_tabResultTabs.setSelectedIndex(0);
759784
}
785+
786+
@Override
787+
protected void finalize()
788+
{
789+
if(false == _session.isClosed())
790+
{
791+
s_log.info("Result tab finalized for open Session \"" + _session.getTitle() + "\" with id=" + _session.getIdentifier());
792+
}
793+
}
760794
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package net.sourceforge.squirrel_sql.client.session.mainpanel;
2+
3+
@FunctionalInterface
4+
public interface ResultTabCloseListener
5+
{
6+
void resultTabClosed();
7+
}

sql12/core/src/net/sourceforge/squirrel_sql/client/session/mainpanel/resulttabactions/ResultTabProvider.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ public class ResultTabProvider
1212
public ResultTabProvider(IResultTab resultTab)
1313
{
1414
_resultTab = resultTab;
15+
16+
if(null != _resultTab)
17+
{
18+
_resultTab.addResultTabCloseListener(() -> _resultTab = null);
19+
}
1520
}
1621

1722
public boolean setSQLPanelAPI(ISQLPanelAPI panel)

sql12/core/src/net/sourceforge/squirrel_sql/client/session/mainpanel/resulttabheader/ResultTabMatchingCurrentSqlHandler.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,17 @@ public void close()
152152
return;
153153
}
154154

155-
_paintTimer.stop();
156-
_entryPanel.removeTextAreaPaintListener(_textAreaPaintListener);
155+
try
156+
{
157+
_paintTimer.stop();
158+
_paintTimer = null;
159+
_entryPanel.removeTextAreaPaintListener(_textAreaPaintListener);
160+
_textAreaPaintListener = null;
161+
}
162+
finally
163+
{
164+
_resultTabHeaderMarkingActive = false;
165+
}
166+
157167
}
158168
}

sql12/core/src/net/sourceforge/squirrel_sql/fw/datasetviewer/coloring/NullValueColorHandler.java

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
import net.sourceforge.squirrel_sql.fw.datasetviewer.DataSetViewerTable;
77

88
import java.awt.Color;
9-
import java.beans.PropertyChangeEvent;
109

1110
public class NullValueColorHandler
1211
{
1312
private boolean _colorNullValues;
1413
private DataSetViewerTable _dataSetViewerTable;
1514
private Color _nullValueColor;
15+
private long _lastPropertiesCheckTime;
1616

1717
public NullValueColorHandler(DataSetViewerTable dataSetViewerTable)
1818
{
@@ -29,31 +29,39 @@ public NullValueColorHandler(DataSetViewerTable dataSetViewerTable)
2929
{
3030
_nullValueColor = new Color(session.getProperties().getNullValueColorRGB());
3131
_colorNullValues = session.getProperties().isColorNullValues();
32-
session.getProperties().addPropertyChangeListener(evt -> onPropertyChange(evt));
3332
}
3433

35-
36-
}
37-
38-
private void onPropertyChange(PropertyChangeEvent evt)
39-
{
40-
if(SessionProperties.IPropertyNames.COLOR_NULL_VALUES.equals(evt.getPropertyName())
41-
|| SessionProperties.IPropertyNames.NULL_VALUE_COLOR_RGB.equals(evt.getPropertyName())
42-
)
43-
{
44-
_nullValueColor = new Color(_dataSetViewerTable.getSessionOrNull().getProperties().getNullValueColorRGB());
45-
_colorNullValues = _dataSetViewerTable.getSessionOrNull().getProperties().isColorNullValues();
46-
_dataSetViewerTable.repaint();
47-
}
34+
_lastPropertiesCheckTime = System.currentTimeMillis();
4835
}
4936

5037
public Color getNullValueColor()
5138
{
39+
checkForPropertiesUpdates();
5240
return _nullValueColor;
5341
}
5442

5543
public boolean isColorNullValues()
5644
{
45+
checkForPropertiesUpdates();
5746
return _colorNullValues;
5847
}
48+
49+
private void checkForPropertiesUpdates()
50+
{
51+
long currentTimeMillis = System.currentTimeMillis();
52+
if(currentTimeMillis - _lastPropertiesCheckTime < 2000)
53+
{
54+
return;
55+
}
56+
57+
_lastPropertiesCheckTime = currentTimeMillis;
58+
59+
if( _nullValueColor.getRGB() != _dataSetViewerTable.getSessionOrNull().getProperties().getNullValueColorRGB()
60+
|| _colorNullValues != _dataSetViewerTable.getSessionOrNull().getProperties().isColorNullValues())
61+
{
62+
_nullValueColor = new Color(_dataSetViewerTable.getSessionOrNull().getProperties().getNullValueColorRGB());
63+
_colorNullValues = _dataSetViewerTable.getSessionOrNull().getProperties().isColorNullValues();
64+
_dataSetViewerTable.repaint();
65+
}
66+
}
5967
}

sql12/core/src/net/sourceforge/squirrel_sql/fw/gui/action/makeeditable/MakeEditableToolbarCtrl.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
1414
import net.sourceforge.squirrel_sql.fw.util.Utilities;
1515

16-
import javax.swing.*;
16+
import javax.swing.JOptionPane;
17+
import javax.swing.JTable;
18+
import javax.swing.JToggleButton;
1719
import java.sql.SQLException;
1820
import java.util.ArrayList;
1921
import java.util.List;
@@ -22,15 +24,19 @@ public class MakeEditableToolbarCtrl
2224
{
2325
private static final StringManager s_stringMgr = StringManagerFactory.getStringManager(MakeEditableToolbarCtrl.class);
2426

25-
26-
private final ResultTab _resultTab;
27+
private ResultTab _resultTab;
2728
private final ISession _session;
2829
private JToggleButton _button;
2930

3031
public MakeEditableToolbarCtrl(ResultTab resultTab, ISession session)
3132
{
3233
_resultTab = resultTab;
3334
_session = session;
35+
36+
if(null != _resultTab)
37+
{
38+
_resultTab.addResultTabCloseListener(() -> _resultTab = null);
39+
}
3440
}
3541

3642
public JToggleButton getTabButton()

0 commit comments

Comments
 (0)