[Fb-contrib-commit] fb-contrib/src/com/mebigfatguy/fbcontrib/detect PossibleMemoryBloat.java,NONE,1.
Brought to you by:
dbrosius
From: Dave B. <dbr...@us...> - 2006-03-07 06:17:28
|
Update of /cvsroot/fb-contrib/fb-contrib/src/com/mebigfatguy/fbcontrib/detect In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24111/src/com/mebigfatguy/fbcontrib/detect Added Files: PossibleMemoryBloat.java Log Message: initial checkin - new PMB detector --- NEW FILE: PossibleMemoryBloat.java --- package com.mebigfatguy.fbcontrib.detect; import java.util.HashSet; 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.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.FieldAnnotation; import edu.umd.cs.findbugs.OpcodeStack; import edu.umd.cs.findbugs.StatelessDetector; import edu.umd.cs.findbugs.ba.ClassContext; /** * 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 this members. * Such member variables are likely causes of memory bloat. * */ public class PossibleMemoryBloat extends BytecodeScanningDetector implements StatelessDetector { private static final Set<String> bloatableSigs = new HashSet<String>(); static { bloatableSigs.add("Ljava/util/ArrayList;"); bloatableSigs.add("Ljava/util/Collection;"); bloatableSigs.add("Ljava/util/HashMap;"); bloatableSigs.add("Ljava/util/HashSet;"); bloatableSigs.add("Ljava/util/Hashtable;"); bloatableSigs.add("Ljava/util/IdentityHashMap;"); bloatableSigs.add("Ljava/util/LinkedHashMap;"); bloatableSigs.add("Ljava/util/LinkedList;"); bloatableSigs.add("Ljava/util/List;"); bloatableSigs.add("Ljava/util/Map;"); bloatableSigs.add("Ljava/util/Set;"); bloatableSigs.add("Ljava/util/SortedSet;"); bloatableSigs.add("Ljava/util/SortedMap;"); bloatableSigs.add("Ljava/util/Stack;"); bloatableSigs.add("Ljava/lang/StringBuffer;"); bloatableSigs.add("Ljava/lang/StringBuilder;"); bloatableSigs.add("Ljava/util/TreeMap;"); bloatableSigs.add("Ljava/util/TreeSet;"); bloatableSigs.add("Ljava/util/Vector;"); } private static final Set<String> clearingMethods = new HashSet<String>(); static { clearingMethods.add("clear"); clearingMethods.add("delete"); clearingMethods.add("deleteCharAt"); clearingMethods.add("pop"); clearingMethods.add("remove"); clearingMethods.add("setLength"); } private BugReporter bugReporter; private Set<FieldAnnotation> bloatableFields = new HashSet<FieldAnnotation>(); private OpcodeStack stack = new OpcodeStack(); /** * constructs a PMB detector given the reporter to report bugs on * @param bugReporter the sync of bug reports */ public PossibleMemoryBloat(BugReporter bugReporter) { this.bugReporter = bugReporter; } /** * clone this detector so that it can be a StatelessDetector * * @return a clone of this object */ @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } /** * collects static fields that are likely bloatable objects and if found * allows the visitor to proceed, at the end report all leftover fields * * @param obj the class context object of the currently parsed java class */ @Override public void visitClassContext(ClassContext classContext) { bloatableFields.clear(); JavaClass cls = classContext.getJavaClass(); Field[] fields = cls.getFields(); for (Field f : fields) { if (f.isStatic()) { String sig = f.getSignature(); if (bloatableSigs.contains(sig)) { bloatableFields.add(FieldAnnotation.fromBCELField(cls.getClassName(), f)); } } } if (bloatableFields.size() > 0) { super.visitClassContext(classContext); for (FieldAnnotation fa : bloatableFields) { bugReporter.reportBug(new BugInstance(this, "PMB_POSSIBLE_MEMORY_BLOAT", NORMAL_PRIORITY) .addClass(this) .addField(fa)); } } } /** * implements the visitor to reset the opcode stack * * @param obj the context object of the currently parsed code block */ @Override public void visitCode(Code obj) { stack.resetForMethodEntry(this); if (bloatableFields.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 * * @param obj the context object of the currently parsed instruction */ @Override public void sawOpcode(int seen) { try { stack.mergeJumps(this); if (bloatableFields.size() == 0) return; if ((seen == INVOKEVIRTUAL) || (seen == INVOKEINTERFACE)) { String sig = getSigConstantOperand(); int argCount = Type.getArgumentTypes(sig).length; if (stack.getStackDepth() > argCount) { OpcodeStack.Item itm = stack.getStackItem(argCount); FieldAnnotation fa = itm.getField(); if (fa != null) { if (bloatableFields.contains(fa)) { String methodName = getNameConstantOperand(); if (clearingMethods.contains(methodName)) { bloatableFields.remove(fa); } } } } } } finally { stack.sawOpcode(this, seen); } } } |