Skip to content
Permalink
Browse files
[JENKINS-21921] Lazy loaded report details are never released
- SloccountResult.lazyLoad() caches the data to a member variable. SloccountResult objects (all build.xml files) are loaded during Jenkins startup and never released so Java garbage collector has no chance to trash the lazy loaded details since the reference exists forever. This is kind of a memory leak.
- Lazy loading reads the data everytime and doesn't use any cache, saving of memory is now prefered to performace. It is not expected the user will show the details very often, so it should be ok.
- Explicit calls of convertLegacyData() replaced by readResolve() from Java serialization with the same effect.
- Report object made transient, null is always passed in SloccountPublisher while storing.
  • Loading branch information
mixalturek committed Mar 12, 2014
1 parent f336a18 commit 32b1fa89cbe28eeb0831db3d1f9dae39bb102a35
Showing 1 changed file with 22 additions and 23 deletions.
@@ -11,7 +11,7 @@
import hudson.plugins.sloccount.model.SloccountReportStatistics;

import java.io.Serializable;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.List;

/**
@@ -22,7 +22,8 @@ public class SloccountResult implements Serializable {
/** Serial version UID. */
private static final long serialVersionUID = 0L;

private SloccountReport report;
private transient SloccountReport report;

private final AbstractBuild<?,?> owner;

/** The statistics. */
@@ -40,8 +41,7 @@ public SloccountResult(SloccountReportStatistics statistics, String encoding,
}

public SloccountReport getReport() {
lazyLoad();
return report;
return lazyLoadReport();
}

public AbstractBuild<?,?> getOwner() {
@@ -54,56 +54,55 @@ public AbstractBuild<?,?> getOwner() {
* @return the statistics, always non-null value
*/
public SloccountReportStatistics getStatistics() {
convertLegacyData();
return statistics;
}

/**
* Convert legacy data in format of sloccount plugin version 1.10
* to the new one that uses statistics.
* Convert legacy data in format of plugin version 1.10 to the new one that
* uses statistics.
*
* If statistics are null for any reason, the object will be created.
* Statistics will be always non-null after this method is called (side
* effect).
* @return this with optionally updated data
*/
private void convertLegacyData() {
if(statistics != null) {
return;
}

List<SloccountLanguageStatistics> languages = new LinkedList<SloccountLanguageStatistics>();
private Object readResolve() {
if (report != null && statistics == null) {
List<SloccountLanguageStatistics> languages = new ArrayList<SloccountLanguageStatistics>();

if(report != null) {
for(Language language : report.getLanguages()){
languages.add(new SloccountLanguageStatistics(language.getName(),
language.getLineCount(), language.getFileCount()));
}

statistics = new SloccountReportStatistics(languages);
}

// Just for sure
if (statistics == null) {
statistics = new SloccountReportStatistics(new ArrayList<SloccountLanguageStatistics>());
}

statistics = new SloccountReportStatistics(languages);
return this;
}

/**
* Lazy load report data if they are not already loaded.
*/
private void lazyLoad() {
private SloccountReport lazyLoadReport() {
if(report != null) {
return;
return report;
}

java.io.File destDir = new java.io.File(owner.getRootDir(),
SloccountPublisher.BUILD_SUBDIR);

if (!destDir.exists()) {
report = new SloccountReport();
return;
return new SloccountReport();
}

String realEncoding = (encoding != null && !encoding.isEmpty())
? encoding : SloccountPublisher.DEFAULT_ENCODING;

SloccountParser parser = new SloccountParser(realEncoding, null, null);
report = parser.parseFiles(destDir.listFiles());
return parser.parseFiles(destDir.listFiles());
}

/**

0 comments on commit 32b1fa8

Please sign in to comment.