From 347c13143bd4188649cda12b7e8349cd8efdf72e Mon Sep 17 00:00:00 2001 From: Nate Jensen Date: Thu, 23 Aug 2012 18:18:23 -0500 Subject: [PATCH] Issue #1096 fix memory leaks in CcfpResource Change-Id: Icccd4d3811327b9a1dcfdf6a5a2cc714ff92afbc Former-commit-id: 73f428e4d558e59af13ca8d9975593ca7ba59640 [formerly 5e9d7763442ab91cb8d33c16139eb5bca9b033ea] Former-commit-id: 047441f91cd1065f0bfaf8c585f8b4fb7a144df0 --- .../uf/viz/ccfp/rsc/CcfpResource.java | 108 +++++++++++++----- .../uf/viz/ccfp/rsc/CcfpResourceData.java | 40 ++++--- 2 files changed, 105 insertions(+), 43 deletions(-) diff --git a/cave/com.raytheon.uf.viz.ccfp/src/com/raytheon/uf/viz/ccfp/rsc/CcfpResource.java b/cave/com.raytheon.uf.viz.ccfp/src/com/raytheon/uf/viz/ccfp/rsc/CcfpResource.java index f2bd70a70f..543b7370c5 100644 --- a/cave/com.raytheon.uf.viz.ccfp/src/com/raytheon/uf/viz/ccfp/rsc/CcfpResource.java +++ b/cave/com.raytheon.uf.viz.ccfp/src/com/raytheon/uf/viz/ccfp/rsc/CcfpResource.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; @@ -63,6 +64,7 @@ import com.vividsolutions.jts.geom.Point; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Sep 22, 2009 3072 bsteffen Initial creation + * Aug 23, 2012 1096 njensen Fixed memory leaks * * * @@ -161,8 +163,10 @@ public class CcfpResource extends } private void disposeFrames() { - for (DisplayFrame frame : frames.values()) { - frame.dispose(); + synchronized (frames) { + for (DisplayFrame frame : frames.values()) { + frame.dispose(); + } } } @@ -180,11 +184,15 @@ public class CcfpResource extends @Override public String inspect(ReferencedCoordinate coord) throws VizException { - if (frames.get(this.displayedDataTime) == null) { + DisplayFrame frame = null; + synchronized (frames) { + frame = frames.get(this.displayedDataTime); + } + if (frame == null) { return ""; } StringBuilder res = new StringBuilder(); - for (CcfpRecord record : frames.get(this.displayedDataTime).records) { + for (CcfpRecord record : frame.records) { // Check if we have an area we are rendering if (isPaintingArea(record)) { try { @@ -216,15 +224,20 @@ public class CcfpResource extends */ private void updateRecords(IGraphicsTarget target, PaintProperties paintProps) throws VizException { - DisplayFrame frame = frames.get(this.displayedDataTime); - if (frame == null) { - frame = new DisplayFrame(); - frames.put(this.displayedDataTime, frame); + DisplayFrame frame = null; + synchronized (frames) { + frame = frames.get(this.displayedDataTime); + if (frame == null) { + frame = new DisplayFrame(); + frames.put(this.displayedDataTime, frame); + } } // Add all the new Records - Collection newRecords = unprocessedRecords - .get(this.displayedDataTime); + Collection newRecords = null; + synchronized (unprocessedRecords) { + newRecords = unprocessedRecords.get(this.displayedDataTime); + } for (CcfpRecord record : newRecords) { // If we need to draw anything for this record then keep it if (isPaintingArea(record) || isPaintingMovement(record) @@ -259,14 +272,19 @@ public class CcfpResource extends this.displayedDataTime = paintProps.getDataTime(); // First check to see if we need to process new data - Collection unprocessed = unprocessedRecords - .get(this.displayedDataTime); + Collection unprocessed = null; + synchronized (unprocessedRecords) { + unprocessed = unprocessedRecords.get(this.displayedDataTime); + } if (unprocessed != null && unprocessed.size() > 0) { updateRecords(target, paintProps); } // Hopefully we now have some data to display, if not bail - DisplayFrame frame = frames.get(this.displayedDataTime); + DisplayFrame frame = null; + synchronized (frames) { + frame = frames.get(this.displayedDataTime); + } if (frame == null) { this.displayedDataTime = null; return; @@ -509,14 +527,24 @@ public class CcfpResource extends */ protected void addRecord(CcfpRecord obj) { DataTime dataTime = obj.getDataTime(); - Collection records = unprocessedRecords.get(dataTime); - if (records == null) { - records = new ArrayList(); - unprocessedRecords.put(dataTime, records); - this.dataTimes.add(dataTime); - Collections.sort(this.dataTimes); + if (resourceData.durationMatches(dataTime)) { + Collection records = null; + boolean brandNew = false; + synchronized (unprocessedRecords) { + records = unprocessedRecords.get(dataTime); + if (records == null) { + records = new HashSet(); + unprocessedRecords.put(dataTime, records); + brandNew = true; + } + } + if (brandNew) { + this.dataTimes.add(dataTime); + Collections.sort(this.dataTimes); + } + + records.add(obj); } - records.add(obj); } @Override @@ -677,16 +705,40 @@ public class CcfpResource extends @Override public void project(CoordinateReferenceSystem crs) throws VizException { - disposeFrames(); - // add as unprocessed to make sure frames created - for (DataTime time : frames.keySet()) { - DisplayFrame frame = frames.get(time); - if (frame != null) { - List copyList = new ArrayList( - frame.records); - unprocessedRecords.put(time, copyList); + synchronized (frames) { + disposeFrames(); + // add as unprocessed to make sure frames created + for (DataTime time : frames.keySet()) { + DisplayFrame frame = frames.get(time); + if (frame != null) { + List copyList = new ArrayList( + frame.records); + synchronized (unprocessedRecords) { + unprocessedRecords.put(time, copyList); + } + } } } } + @Override + public void remove(DataTime time) { + super.remove(time); + Collection notNeeded = null; + synchronized (unprocessedRecords) { + notNeeded = unprocessedRecords.remove(time); + } + if (notNeeded != null) { + notNeeded.clear(); + } + + DisplayFrame frame = null; + synchronized (frames) { + frame = frames.remove(time); + } + if (frame != null) { + frame.dispose(); + } + } + } diff --git a/cave/com.raytheon.uf.viz.ccfp/src/com/raytheon/uf/viz/ccfp/rsc/CcfpResourceData.java b/cave/com.raytheon.uf.viz.ccfp/src/com/raytheon/uf/viz/ccfp/rsc/CcfpResourceData.java index c38b14c474..ae946ce57f 100644 --- a/cave/com.raytheon.uf.viz.ccfp/src/com/raytheon/uf/viz/ccfp/rsc/CcfpResourceData.java +++ b/cave/com.raytheon.uf.viz.ccfp/src/com/raytheon/uf/viz/ccfp/rsc/CcfpResourceData.java @@ -31,12 +31,10 @@ import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.time.DataTime; -import com.raytheon.uf.viz.ccfp.Activator; import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.core.rsc.AbstractRequestableResourceData; import com.raytheon.uf.viz.core.rsc.AbstractVizResource; import com.raytheon.uf.viz.core.rsc.LoadProperties; -import com.raytheon.uf.viz.core.status.StatusConstants; /** * @@ -56,8 +54,9 @@ import com.raytheon.uf.viz.core.status.StatusConstants; */ @XmlAccessorType(XmlAccessType.NONE) public class CcfpResourceData extends AbstractRequestableResourceData { - private static final transient IUFStatusHandler statusHandler = UFStatus.getHandler(CcfpResourceData.class); - + private static final transient IUFStatusHandler statusHandler = UFStatus + .getHandler(CcfpResourceData.class); + // This flag determnies if we draw lines and polygons @XmlAttribute private boolean displayArea = true; @@ -69,35 +68,34 @@ public class CcfpResourceData extends AbstractRequestableResourceData { // This flag determines if we display text boxes @XmlAttribute private boolean displayText = true; - + // Filter by coverage @XmlAttribute private int coverageFilter = 0; - - + @XmlAttribute private int validDuration = 0; - + @Override public boolean equals(Object obj) { if (!super.equals(obj)) { return false; } - + if (obj instanceof CcfpResourceData == false) { return false; } - + CcfpResourceData other = (CcfpResourceData) obj; if (other.coverageFilter != this.coverageFilter) { return false; } - + if (other.validDuration != this.validDuration) { return false; } - + if (other.displayText != this.displayText) { return false; } @@ -109,7 +107,7 @@ public class CcfpResourceData extends AbstractRequestableResourceData { if (other.displayMovement != this.displayMovement) { return false; } - + return true; } @@ -122,7 +120,7 @@ public class CcfpResourceData extends AbstractRequestableResourceData { DataTime[] originalTimes = super.getAvailableTimes(); ArrayList newTimes = new ArrayList(); for (DataTime time : originalTimes) { - if (time.getValidPeriod().getDuration() == validDuration * 1000) { + if (durationMatches(time)) { newTimes.add(time); } } @@ -147,6 +145,18 @@ public class CcfpResourceData extends AbstractRequestableResourceData { return nr; } + /** + * Checks if a DataTime's valid period matches the duration of the resource + * data + * + * @param time + * the time to check + * @return true if the durations are equal, otherwise false + */ + protected boolean durationMatches(DataTime time) { + return time.getValidPeriod().getDuration() == validDuration * 1000; + } + public boolean isDisplayArea() { return displayArea; } @@ -185,6 +195,6 @@ public class CcfpResourceData extends AbstractRequestableResourceData { public void setValidDuration(int validDuration) { this.validDuration = validDuration; - } + } }