private void visitRootObj(LeakNode node) { RootObj rootObj = (RootObj) node.instance; Instance child = rootObj.getReferredInstance(); Exclusion exclusion = rootSuperClassAlwaysIgnored(child); if (exclusion != null && exclusion.alwaysExclude) { return; } if (rootObj.getRootType() == RootType.JAVA_LOCAL) { Instance holder = HahaSpy.allocatingThread(rootObj); // We switch the parent node with the thread instance that holds // the local reference. LeakNode parent = new LeakNode(null, holder, null, null, null); if (node.exclusion != null) { exclusion = node.exclusion; } enqueue(exclusion, parent, child, "<Java Local>", LOCAL); } else { enqueue(exclusion, node, child, null, null); } }
private Exclusion rootSuperClassAlwaysIgnored(Instance child) { if (child == null) { return null; } Exclusion matchingParams = null; ClassObj superClassObj = child.getClassObj(); while (superClassObj != null) { Exclusion params = excludedRefs.rootClassNames.get(superClassObj.getClassName()); if (params != null) { // true overrides null or false. if (matchingParams == null || !matchingParams.alwaysExclude) { matchingParams = params; } } superClassObj = superClassObj.getSuperClassObj(); } return matchingParams; }
private void visitClassObj(LeakNode node) { ClassObj classObj = (ClassObj) node.instance; Map<String, Exclusion> ignoredStaticFields = excludedRefs.staticFieldNameByClassName.get(classObj.getClassName()); for (Map.Entry<Field, Object> entry : classObj.getStaticFieldValues().entrySet()) { Field field = entry.getKey(); if (field.getType() != Type.OBJECT) { continue; } String fieldName = field.getName(); if (fieldName.equals("$staticOverhead")) { continue; } Instance child = (Instance) entry.getValue(); boolean visit = true; if (ignoredStaticFields != null) { Exclusion params = ignoredStaticFields.get(fieldName); if (params != null) { visit = false; if (!params.alwaysExclude) { enqueue(params, node, child, fieldName, STATIC_FIELD); } } } if (visit) { enqueue(null, node, child, fieldName, STATIC_FIELD); } } }
private void enqueue(Exclusion exclusion, LeakNode parent, Instance child, String referenceName, LeakTraceElement.Type referenceType) { if (child == null) { return; } if (isPrimitiveOrWrapperArray(child) || isPrimitiveWrapper(child)) { return; } // Whether we want to visit now or later, we should skip if this is already to visit. if (toVisitSet.contains(child)) { return; } boolean visitNow = exclusion == null; if (!visitNow && toVisitIfNoPathSet.contains(child)) { return; } if (canIgnoreStrings && isString(child)) { return; } if (visitedSet.contains(child)) { return; } LeakNode childNode = new LeakNode(exclusion, child, parent, referenceName, referenceType); if (visitNow) { toVisitSet.add(child); toVisitQueue.add(childNode); } else { toVisitIfNoPathSet.add(child); toVisitIfNoPathQueue.add(childNode); } }
LeakNode(Exclusion exclusion, Instance instance, LeakNode parent, String referenceName, LeakTraceElement.Type referenceType) { this.exclusion = exclusion; this.instance = instance; this.parent = parent; this.referenceName = referenceName; this.referenceType = referenceType; }
private String elementToHtmlString(LeakTraceElement element, boolean root, boolean opened) { String htmlString = ""; if (element.referenceName == null) { htmlString += "leaks "; } else if (!root) { htmlString += "references "; } if (element.type == STATIC_FIELD) { htmlString += "<font color='#c48a47'>static</font> "; } if (element.holder == ARRAY || element.holder == THREAD) { htmlString += "<font color='#f3cf83'>" + element.holder.name().toLowerCase() + "</font> "; } int separator = element.className.lastIndexOf('.'); String qualifier; String simpleName; if (separator == -1) { qualifier = ""; simpleName = element.className; } else { qualifier = element.className.substring(0, separator + 1); simpleName = element.className.substring(separator + 1); } if (opened) { htmlString += "<font color='#919191'>" + qualifier + "</font>"; } String styledClassName = "<font color='#ffffff'>" + simpleName + "</font>"; htmlString += styledClassName; if (element.referenceName != null) { htmlString += ".<font color='#998bb5'>" + element.referenceName.replaceAll("<", "<") .replaceAll(">", ">") + "</font>"; } else { htmlString += " <font color='#f3cf83'>instance</font>"; } if (opened && element.extra != null) { htmlString += " <font color='#919191'>" + element.extra + "</font>"; } Exclusion exclusion = element.exclusion; if (exclusion != null) { if (opened) { htmlString += "<br/><br/>Excluded by rule"; if (exclusion.name != null) { htmlString += " <font color='#ffffff'>" + exclusion.name + "</font>"; } htmlString += " matching <font color='#f3cf83'>" + exclusion.matching + "</font>"; if (exclusion.reason != null) { htmlString += " because <font color='#f3cf83'>" + exclusion.reason + "</font>"; } } else { htmlString += " (excluded)"; } } return htmlString; }
private void enqueueGcRoots(Snapshot snapshot) { for (RootObj rootObj : snapshot.getGCRoots()) { switch (rootObj.getRootType()) { case JAVA_LOCAL: Instance thread = HahaSpy.allocatingThread(rootObj); String threadName = threadName(thread); Exclusion params = excludedRefs.threadNames.get(threadName); if (params == null || !params.alwaysExclude) { enqueue(params, null, rootObj, null, null); } break; case INTERNED_STRING: case DEBUGGER: case INVALID_TYPE: // An object that is unreachable from any other root, but not a root itself. case UNREACHABLE: case UNKNOWN: // An object that is in a queue, waiting for a finalizer to run. case FINALIZING: break; case SYSTEM_CLASS: case VM_INTERNAL: // A local variable in native code. case NATIVE_LOCAL: // A global variable in native code. case NATIVE_STATIC: // An object that was referenced from an active thread block. case THREAD_BLOCK: // Everything that called the wait() or notify() methods, or that is synchronized. case BUSY_MONITOR: case NATIVE_MONITOR: case REFERENCE_CLEANUP: // Input or output parameters in native code. case NATIVE_STACK: case JAVA_STATIC: enqueue(null, null, rootObj, null, null); break; default: throw new UnsupportedOperationException("Unknown root type:" + rootObj.getRootType()); } } }