Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * fb-contrib - Auxiliary detectors for Java programs
   * Copyright (C) 2005-2013 Dave Brosius
   * 
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   * 
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  * 
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 package com.mebigfatguy.fbcontrib.detect;
 
 import java.util.Map;
 import java.util.Set;
 
 import  org.apache.bcel.classfile.Code;
 import  org.apache.bcel.classfile.Field;
 import  org.apache.bcel.classfile.JavaClass;
 import  org.apache.bcel.classfile.Method;
 import  org.apache.bcel.generic.Type;
 
 import  edu.umd.cs.findbugs.BugInstance;
 import  edu.umd.cs.findbugs.BugReporter;
 import  edu.umd.cs.findbugs.BytecodeScanningDetector;
 import  edu.umd.cs.findbugs.OpcodeStack;
 import  edu.umd.cs.findbugs.SourceLineAnnotation;
 import  edu.umd.cs.findbugs.ba.ClassContext;
 import  edu.umd.cs.findbugs.ba.XFactory;
 import  edu.umd.cs.findbugs.ba.XField;

looks for classes that maintain collections or StringBuffer/StringBuilders in static member variables, and that do not appear to provide a way to clear or remove items from these members. Such class fields are likely causes of memory bloat.
 
 public class PossibleMemoryBloat extends BytecodeScanningDetector
 {
 	private static final Set<StringbloatableSigs = new HashSet<String>();
 	static {
         .add("Ljava/util/concurrent/ArrayBlockingQueue;");
         .add("Ljava/util/ArrayList;");
         .add("Ljava/util/concurrent/BlockingQueue;");		
         .add("Ljava/util/Collection;");
         .add("Ljava/util/concurrent/ConcurrentHashMap;");
         .add("Ljava/util/concurrent/ConcurrentSkipListMap;");
         .add("Ljava/util/concurrent/ConcurrentSkipListSet;");
         .add("Ljava/util/concurrent/CopyOnWriteArraySet;");
         .add("Ljava/util/EnumSet;");
         .add("Ljava/util/EnumMap;");
 		.add("Ljava/util/HashMap;");
 		.add("Ljava/util/HashSet;");
 		.add("Ljava/util/Hashtable;");
 		.add("Ljava/util/IdentityHashMap;");
         .add("Ljava/util/concurrent/LinkedBlockingQueue;");
         .add("Ljava/util/LinkedHashMap;");
         .add("Ljava/util/LinkedHashSet;");
 		.add("Ljava/util/LinkedList;");
         .add("Ljava/util/List;");
         .add("Ljava/util/concurrent/PriorityBlockingQueue;");
         .add("Ljava/util/PriorityQueue;");
 		.add("Ljava/util/Map;");
 	    .add("Ljava/util/Queue;");
 		.add("Ljava/util/Set;");
 		.add("Ljava/util/SortedSet;");
 		.add("Ljava/util/SortedMap;");
 		.add("Ljava/util/Stack;");
 		.add("Ljava/lang/StringBuffer;");
 		.add("Ljava/lang/StringBuilder;");
 		.add("Ljava/util/TreeMap;");
 		.add("Ljava/util/TreeSet;");
 		.add("Ljava/util/Vector;");
 	}
 	private static final Set<StringdecreasingMethods = new HashSet<String>();
 	static {
 		.add("delete");
         .add("deleteCharAt");
         .add("drainTo");
         .add("poll");
         .add("pollFirst");
         .add("pollLast");
         .add("pop");
 		.add("remove");
 		.add("removeAll");
 		.add("removeAllElements");
 		.add("removeElementAt");
 		.add("removeRange");
         .add("setLength");
        .add("take");
	}
	private static final Set<StringincreasingMethods = new HashSet<String>();
	static {
		.add("addElement");
		.add("insertElementAt");
        .add("offer");
        .add("put");
	}
	private final BugReporter bugReporter;
	private Map<XField, SourceLineAnnotation> bloatableFields;
	private OpcodeStack stack;
	private String methodName;

constructs a PMB detector given the reporter to report bugs on

Parameters:
bugReporter the sync of bug reports
	public PossibleMemoryBloat(BugReporter bugReporter) {
		this. = bugReporter;
	}

collects static fields that are likely bloatable objects and if found allows the visitor to proceed, at the end report all leftover fields

Parameters:
classContext the class context object of the currently parsed java class
	public void visitClassContext(ClassContext classContext) {
		try {
			 = new HashMap<XField, SourceLineAnnotation>();
			JavaClass cls = classContext.getJavaClass();
			Field[] fields = cls.getFields();
			for (Field f : fields) {
				if (f.isStatic()) {
					String sig = f.getSignature();
					if (.contains(sig)) {
						.put(XFactory.createXField(cls.getClassName(), f.getName(), f.getSignature(), f.isStatic()), null);
					}
				}
			}
			if (.size() > 0) {
				 = new OpcodeStack();
				super.visitClassContext(classContext);
				for (Map.Entry<XField, SourceLineAnnotation> entry : .entrySet()) {
					SourceLineAnnotation sla = entry.getValue();
					if (sla != null) {
						.reportBug(new BugInstance(this"PMB_POSSIBLE_MEMORY_BLOAT", NORMAL_PRIORITY)
									.addClass(this)
									.addSourceLine(sla)
									.addField(entry.getKey()));
					}
				}
			}
finally {
			 = null;
		}
	}

implements the visitor to collect the method name

Parameters:
obj the context object of the currently parsed method
	public void visitMethod(Method obj) {
		 = obj.getName();
	}

implements the visitor to reset the opcode stack

Parameters:
obj the context object of the currently parsed code block
	public void visitCode(Code obj) {
		.resetForMethodEntry(this);
		if ("<clinit>".equals()
		||  "<init>".equals())
			return;
		if (.size() > 0)
			super.visitCode(obj);
	}

implements the visitor to look for methods that empty a bloatable field if found, remove these fields from the current list

Parameters:
seen the opcode of the currently parsed instruction
	public void sawOpcode(int seen) {
		try {
			if (.isEmpty())
				return;
	        .precomputation(this);
	        
			if ((seen == INVOKEVIRTUAL)
			||  (seen == INVOKEINTERFACE)) {
				int argCount = Type.getArgumentTypes(sig).length;
				if (.getStackDepth() > argCount) {
					OpcodeStack.Item itm = .getStackItem(argCount);
					XField field = itm.getXField();
					if (field != null) {
						if (.containsKey(field)) {
								.remove(field);
else if (.contains(mName)) {
								if (.get(field) == null) {
									SourceLineAnnotation sla = SourceLineAnnotation.fromVisitedInstruction(this);
									.put(fieldsla);
								}
							}
						}
					}
				}
			}
			else if (seen == ARETURN) {
			    if (.getStackDepth() > 0) {
			        OpcodeStack.Item returnItem = .getStackItem(0);
			        XField field = returnItem.getXField();
			        if (field != null) {
			            .remove(field);
			        }
			    }
			}
		}
		finally {
			.sawOpcode(thisseen);
		}
	}
New to GrepCode? Check out our FAQ X