Author: psmith
Date: Tue Sep  9 22:15:02 2008
New Revision: 693706

URL: http://svn.apache.org/viewvc?rev=693706&view=rev
Log:
Bug 42670 - Fixed memory leak in cyclic buffer mode.

The CyclicBufferListModel is designed to reduce memory consumption but over 
time a HashSet keeping track of duplicate event IDs grows forever.

When the cyclic buffer is full, the oldest event will drop off the cliff, so 
just prior to that we remove it's event ID from the HashSet.

Modified:
    logging/chainsaw/trunk/src/changes/changes.xml
    
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java

Modified: logging/chainsaw/trunk/src/changes/changes.xml
URL: 
http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/changes/changes.xml?rev=693706&r1=693705&r2=693706&view=diff
==============================================================================
--- logging/chainsaw/trunk/src/changes/changes.xml (original)
+++ logging/chainsaw/trunk/src/changes/changes.xml Tue Sep  9 22:15:02 2008
@@ -33,9 +33,10 @@
        <action dev="psmith" issue="43158" type="add" due-to="Isuru 
Suriarachchi" due-to-email="">
                Added ability to remember last created receivers in an xml 
file, and load them at startup.
        </action>
-       <action dev="psmith" issue="ASF Bugzilla Bug 42883" type="add" 
due-to="Isuru Suriarachchi" due-to-email="">
+       <action dev="psmith" issue="42883" type="add" due-to="Isuru 
Suriarachchi" due-to-email="">
                Added ability to remember hidden log panels.
        </action>
+       <action dev="psmith" issue="42670" type="fix">Address memory leak when 
using cyclic model</action>
     </release>
   </body>
 </document>

Modified: 
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
URL: 
http://svn.apache.org/viewvc/logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java?rev=693706&r1=693705&r2=693706&view=diff
==============================================================================
--- 
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
 (original)
+++ 
logging/chainsaw/trunk/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
 Tue Sep  9 22:15:02 2008
@@ -28,10 +28,8 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
-import java.awt.EventQueue;
 
 import javax.swing.ProgressMonitor;
-import javax.swing.SwingUtilities;
 import javax.swing.event.EventListenerList;
 import javax.swing.table.AbstractTableModel;
 
@@ -40,8 +38,8 @@
 import org.apache.log4j.chainsaw.helper.SwingHelper;
 import org.apache.log4j.helpers.Constants;
 import org.apache.log4j.rule.Rule;
-import org.apache.log4j.spi.LoggingEvent;
 import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
 
 
 /**
@@ -60,6 +58,7 @@
  */
 class ChainsawCyclicBufferTableModel extends AbstractTableModel
   implements EventContainer, PropertyChangeListener {
+
   private static final int DEFAULT_CAPACITY = 5000;
   private boolean cyclic = true;
   private int cyclicBufferSize = DEFAULT_CAPACITY;
@@ -68,22 +67,22 @@
   Set idSet = new HashSet(cyclicBufferSize);
   private boolean currentSortAscending;
   private int currentSortColumn;
-  private EventListenerList eventListenerList = new EventListenerList();
-  private List columnNames = new ArrayList(ChainsawColumns.getColumnsNames());
+  private final EventListenerList eventListenerList = new EventListenerList();
+  private final List columnNames = new 
ArrayList(ChainsawColumns.getColumnsNames());
   private boolean sortEnabled = false;
   private boolean reachedCapacity = false;
   private final Logger logger = 
LogManager.getLogger(ChainsawCyclicBufferTableModel.class);
 
   //  protected final Object syncLock = new Object();
-  private LoggerNameModel loggerNameModelDelegate =
+  private final LoggerNameModel loggerNameModelDelegate =
     new LoggerNameModelSupport();
 
   //because we may be using a cyclic buffer, if an ID is not provided in the 
property, 
   //use and increment this row counter as the ID for each received row
   int uniqueRow;
-  private Set uniquePropertyKeys = new HashSet();
+  private final Set uniquePropertyKeys = new HashSet();
   private Rule displayRule;
-  private PropertyChangeSupport propertySupport =
+  private final PropertyChangeSupport propertySupport =
     new PropertyChangeSupport(this);
 
   public ChainsawCyclicBufferTableModel(int cyclicBufferSize) {
@@ -92,6 +91,7 @@
 
     unfilteredList = new CyclicBufferList(cyclicBufferSize);
     filteredList = new CyclicBufferList(cyclicBufferSize);
+    idSet = new HashSet(cyclicBufferSize);
   }
 
   /* (non-Javadoc)
@@ -463,6 +463,21 @@
     }
 
     idSet.add(id);
+    
+    /**
+         * If we're in cyclic mode and over budget on the size, the addition 
of a new event will
+         * cause the oldest event to fall off the cliff. We need to remove 
that events ID from the
+         * Set so we are not keeping track of IDs for all events ever received 
(we'd run out of
+         * memory...)
+         */
+    if (isCyclic()) {
+            CyclicBufferList bufferList = (CyclicBufferList) unfilteredList;
+            if (bufferList.size() == bufferList.getMaxSize()) {
+                LoggingEvent aboutToBeDropped = (LoggingEvent) 
unfilteredList.get(0);
+                
idSet.remove(Integer.valueOf(aboutToBeDropped.getProperty(Constants.LOG4J_ID_KEY)));
+                reachedCapacity = true;
+            }
+    }
     unfilteredList.add(e);
 
     if ((displayRule == null) || (displayRule.evaluate(e))) {


Reply via email to