leakcanary shark 库解析 二
1.LeakNodeStatus 三个状态,没用到
internal enum class LeakNodeStatus {
NOT_LEAKING,
LEAKING,
UNKNOWN;
}
2.HeapAnalysisException 封装throwable
class HeapAnalysisException(cause: Throwable) : RuntimeException(cause) {
override fun toString(): String {
val stringWriter = StringWriter()
cause!!.printStackTrace(PrintWriter(stringWriter))
return stringWriter.toString()
}
companion object {
private const val serialVersionUID: Long = -2522323377375290608
}
}
3.AppSingletonInspector App范围内的单例,标记为不泄漏
/**
* Inspector that automatically marks instances of the provided class names as not leaking
* because they're app wide singletons.
* 检查器,自动将提供的类名的实例标记为不泄漏,因为它们是应用程序范围的单例。
*
*/
class AppSingletonInspector(private vararg val singletonClasses: String) : ObjectInspector {
//检查
override fun inspect(
reporter: ObjectReporter//todo ObjectReporter是干哈的
) {
if (reporter.heapObject is HeapInstance) {
reporter.heapObject.instanceClass
.classHierarchy//他自己的类+父类
.forEach { heapClass ->
if (heapClass.name in singletonClasses) {
reporter.notLeakingReasons += "${heapClass.name} is an app singleton"
}
}
}
}
}
4.MetadataExtractor 元数据提取器接口
/**
* Extracts metadata from a hprof to be reported in [HeapAnalysisSuccess.metadata].
*
* This is a functional interface with which you can create a [MetadataExtractor] from a lambda.
* 从 [HeapAnalysisSuccess.metadata] 分析成功的 hprof 中提取元数据。
* 这是一个功能接口,您可以使用它从 lambda 创建 [MetadataExtractor]。
*/
fun interface MetadataExtractor {
fun extractMetadata(graph: HeapGraph): Map<String, String>
companion object {
/**
* A no-op [MetadataExtractor]
*/
val NO_OP = MetadataExtractor { emptyMap() }
/**
* Utility function to create a [MetadataExtractor] from the passed in [block] lambda instead of
* using the anonymous `object : MetadataExtractor` syntax.
*
* Usage:
*
* ```kotlin
* val inspector = MetadataExtractor { graph ->
*
* }
* ```
*/
inline operator fun invoke(crossinline block: (HeapGraph) -> Map<String, String>): MetadataExtractor =
object : MetadataExtractor {
override fun extractMetadata(graph: HeapGraph): Map<String, String> = block(graph)
}
}
}
5.LeakingObjectFinder查找泄漏的对象id们
/**
* Finds the objects that are leaking, for which Shark will compute
* leak traces.
*
* This is a functional interface with which you can create a [LeakingObjectFinder] from a lambda.
* 查找泄漏的对象,Shark 将为其计算泄漏跟踪。
* 这是一个函数式接口,您可以使用它从 lambda 创建 [LeakingObjectFinder]。
*/
fun interface LeakingObjectFinder {
/**
* For a given heap graph, returns a set of object ids for the objects that are leaking.
* 对于给定的堆图,返回一组泄漏对象的对象 ID。
*/
fun findLeakingObjectIds(graph: HeapGraph): Set<Long>
companion object {
/**
* Utility function to create a [LeakingObjectFinder] from the passed in [block] lambda
* instead of using the anonymous `object : LeakingObjectFinder` syntax.
*
* Usage:
*
* ```kotlin
* val listener = LeakingObjectFinder {
*
* }
* ```
*/
inline operator fun invoke(crossinline block: (HeapGraph) -> Set<Long>): LeakingObjectFinder =
object : LeakingObjectFinder {
override fun findLeakingObjectIds(graph: HeapGraph): Set<Long> = block(graph)
}
}
}
6.FilteringLeakingObjectFinder通过扫描堆转储中的所有对象并将决策委托给[FilteringLeakingObjectFinder.LeakingObjectFilter]列表来查找泄漏的对象
/**
* Finds the objects that are leaking by scanning all objects in the heap dump
* and delegating the decision to a list of [FilteringLeakingObjectFinder.LeakingObjectFilter]
* 通过扫描堆转储中的所有对象并将决策委托给[FilteringLeakingObjectFinder.LeakingObjectFilter]列表来查找泄漏的对象
*/
class FilteringLeakingObjectFinder(private val filters: List<LeakingObjectFilter>) :
LeakingObjectFinder {
/**
* Filter to be passed to the [FilteringLeakingObjectFinder] constructor.
* 要传递给[FilteringLeakingObjectFinder]构造函数的筛选器。
*/
interface LeakingObjectFilter {
/**
* Returns whether the passed in [heapObject] is leaking. This should only return true
* when we're 100% sure the passed in [heapObject] should not be in memory anymore.
* 返回传入的[heapObject]是否泄漏。只有当我们100%确定传入的[heapObject]不应再在内存中时,才会返回true。
*/
fun isLeakingObject(heapObject: HeapObject): Boolean
}
override fun findLeakingObjectIds(graph: HeapGraph): Set<Long> {
return graph.objects
.filter { heapObject ->
filters.any { filter ->//any表示至少有一个
filter.isLeakingObject(heapObject)
}
}
.map { it.objectId }
.toSet()
}
}
7.ObjectInspector 对象检查员为 LeakCanary 提供 堆中对象(类、实例和数组)更多的信息。
package shark
/**
* Provides LeakCanary with insights about objects (classes, instances and arrays) found in the
* heap. [inspect] will be called for each object that LeakCanary wants to know more about.
* The implementation can then use the provided [ObjectReporter] to provide insights for that
* object.
*
* 对象检查员 为 LeakCanary 提供 堆中对象(类、实例和数组)更多的信息。
* LeakCanary可以调用[inspect]方法,了解对象更多的信息。
* 实现类可以使用提供的 [ObjectReporter] 来提供该对象的信息。
*
* This is a functional interface with which you can create a [ObjectInspector] from a lambda.
*/
fun interface ObjectInspector {
/**
* @see [ObjectInspector]
*/
fun inspect(reporter: ObjectReporter)// ObjectReporter里边保存着label,leakingReasons,notLeakingReasons
companion object {
/**
* Utility function to create a [ObjectInspector] from the passed in [block] lambda instead of
* using the anonymous `object : OnHeapAnalyzedListener` syntax.
*
* Usage:
*
* ```kotlin
* val inspector = ObjectInspector { reporter ->
*
* }
* ```
*/
inline operator fun invoke(crossinline block: (ObjectReporter) -> Unit): ObjectInspector =
object : ObjectInspector {
override fun inspect(
reporter: ObjectReporter
) {
block(reporter)
}
}
}
}
8.OnAnalysisProgressListener将 [HeapAnalyzer] 的进度报告为 [Step] 值。
/**
* Reports progress from the [HeapAnalyzer] as they occur, as [Step] values.
* 将 [HeapAnalyzer] 的进度报告为 [Step] 值。
*
* This is a functional interface with which you can create a [OnAnalysisProgressListener] from a lambda.
*/
fun interface OnAnalysisProgressListener {
// These steps are defined in the order in which they occur.
//这些步骤按它们发生的顺序定义。
enum class Step {
PARSING_HEAP_DUMP, //解析dump
EXTRACTING_METADATA, //提取metadata
FINDING_RETAINED_OBJECTS, //retained 保留
FINDING_PATHS_TO_RETAINED_OBJECTS,//寻找路径到保留对象
FINDING_DOMINATORS, //寻找统治者
INSPECTING_OBJECTS, //检查对象
COMPUTING_NATIVE_RETAINED_SIZE, //计算原生保留大小
COMPUTING_RETAINED_SIZE,//计算保留大小
BUILDING_LEAK_TRACES, //建立泄漏痕迹
REPORTING_HEAP_ANALYSIS //报告堆分析
}
fun onAnalysisProgress(step: Step)
companion object {
/**
* A no-op [OnAnalysisProgressListener]
*/
val NO_OP = OnAnalysisProgressListener {}
/**
* Utility function to create a [OnAnalysisProgressListener] from the passed in [block] lambda
* instead of using the anonymous `object : OnAnalysisProgressListener` syntax.
*
* Usage:
*
* ```kotlin
* val listener = OnAnalysisProgressListener {
*
* }
* ```
*/
inline operator fun invoke(crossinline block: (Step) -> Unit): OnAnalysisProgressListener =
object : OnAnalysisProgressListener {
override fun onAnalysisProgress(step: Step) {
block(step)
}
}
}
}
9.LeakTraceReference封装LeakTraceObject
/**
* A [LeakTraceReference] represents and origin [LeakTraceObject] and either a reference from that
* object to the [LeakTraceObject] in the next [LeakTraceReference] in [LeakTrace.referencePath],
* or to [LeakTrace.leakingObject] if this is the last [LeakTraceReference] in
* [LeakTrace.referencePath].
*
* [LeakTraceReference] 封装LeakTraceObject
*/
data class LeakTraceReference(
val originObject: LeakTraceObject,
val referenceType: ReferenceType,
val owningClassName: String,
val referenceName: String
) : Serializable {
enum class ReferenceType {
INSTANCE_FIELD,
STATIC_FIELD,
LOCAL,
ARRAY_ENTRY
}
/**
* Returns {@link #className} without the package, ie stripped of any string content before the
* last period (included).
*/
val owningClassSimpleName: String get() = owningClassName.lastSegment('.')
val referenceDisplayName: String
get() {
return when (referenceType) {
ARRAY_ENTRY -> "[$referenceName]"
STATIC_FIELD, INSTANCE_FIELD -> referenceName
LOCAL -> "<Java Local>"
}
}
val referenceGenericName: String//Generic通用的
get() {
return when (referenceType) {
// The specific array index in a leak rarely matters, this improves grouping.
ARRAY_ENTRY -> "[x]"
STATIC_FIELD, INSTANCE_FIELD -> referenceName
LOCAL -> "<Java Local>"
}
}
companion object {
private const val serialVersionUID = 1L
}
}
10.ObjectReporter为ObjectInspector对象检查员提供heapObject相关的信息 , 一个给定的 [ObjectReporter] 只映射到堆中的一个对象,但被许多 [ObjectInspector] 实现共享并积累洞察力。
/**
* Enables [ObjectInspector] implementations to provide insights on [heapObject], which is
* an object (class, instance or array) found in the heap.
*
* A given [ObjectReporter] only maps to one object in the heap, but is shared to many
* [ObjectInspector] implementations and accumulates insights.
*
* 为ObjectInspector对象检查员提供heapObject相关的信息
* 一个给定的 [ObjectReporter] 只映射到堆中的一个对象,但被许多 [ObjectInspector] 实现共享并积累洞察力。
*/
class ObjectReporter constructor(val heapObject: HeapObject) {
/**
* Labels that will be visible on the corresponding [heapObject] in the leak trace.
* 在泄漏跟踪中相应的 [heapObject] 上可见的标签
*/
val labels = linkedSetOf<String>()
/**
* Reasons for which this object is expected to be unreachable (ie it's leaking).
* 预期此对象无法访问的原因(即它正在泄漏)。
*/
val leakingReasons = mutableSetOf<String>()
/**
* Deprecated, use leakingReasons instead.
*/
@Deprecated(
"Replace likelyLeakingReasons with leakingReasons",
replaceWith = ReplaceWith(
"leakingReasons"
)
)
val likelyLeakingReasons
get() = leakingReasons
/**
* Reasons for which this object is expected to be reachable (ie it's not leaking).
* 预期此对象可达的原因(即它没有泄漏)。
*/
val notLeakingReasons = mutableSetOf<String>()
/**
* Runs [block] if [ObjectReporter.heapObject] is an instance of [expectedClass].
* 如果 [ObjectReporter.heapObject] 是 [expectedClass] 的实例,则运行 [block]。
*/
fun whenInstanceOf(
expectedClass: KClass<out Any>,
block: ObjectReporter.(HeapInstance) -> Unit
) {
whenInstanceOf(expectedClass.java.name, block)
}
/**
* Runs [block] if [ObjectReporter.heapObject] is an instance of [expectedClassName].
* 如果 [ObjectReporter.heapObject] 是 [expectedClass] 的实例,则运行 [block]。
*/
fun whenInstanceOf(
expectedClassName: String,
block: ObjectReporter.(HeapInstance) -> Unit
) {
val heapObject = heapObject
if (heapObject is HeapInstance && heapObject instanceOf expectedClassName) {
block(heapObject)
}
}
}
11.ReferenceMatcher用于模式匹配堆中已知的引用模式,要么忽略它们([IgnoredReferenceMatcher]), 要么将它们标记为库泄漏([LibraryLeakReferenceMatcher])。
/**
* Used to pattern match known patterns of references in the heap, either to ignore them
* ([IgnoredReferenceMatcher]) or to mark them as library leaks ([LibraryLeakReferenceMatcher]).
* 用于模式匹配堆中已知的引用模式,要么忽略它们([IgnoredReferenceMatcher]),
* 要么将它们标记为库泄漏([LibraryLeakReferenceMatcher])。
*/
sealed class ReferenceMatcher {
/** The pattern that references will be matched against.
* 引用将匹配的模式 */
abstract val pattern: ReferencePattern
}
/**
* [LibraryLeakReferenceMatcher] should be used to match references in library code that are
* known to create leaks and are beyond your control. The shortest path finder will only go
* through matching references after it has exhausted references that don't match, prioritizing
* finding an application leak over a known library leak. Library leaks will be reported as
* [LibraryLeak] instead of [ApplicationLeak].
* [LibraryLeakReferenceMatcher] 应该用于匹配库代码中已知会造成泄漏并且超出您控制范围的引用。
* 最短路径查找器只会在耗尽不匹配的引用后才通过匹配的引用,优先查找应用程序泄漏而不是已知库泄漏。
* 库泄漏将报告为 [LibraryLeak] 而不是 [ApplicationLeak]。
*/
data class LibraryLeakReferenceMatcher(
override val pattern: ReferencePattern,
/**
* A description that conveys what we know about this library leak.
*/
val description: String = "",
/**
* Whether the identified leak may exist in the provided [HeapGraph]. Defaults to true. If
* the heap dump comes from a VM that runs a different version of the library that doesn't
* have the leak, then this should return false.
* 不同虚拟机可能不用,如果一个虚拟机不可能出现这个问题,则返回false
*/
val patternApplies: (HeapGraph) -> Boolean = { true }
) : ReferenceMatcher() {
override fun toString() = "library leak: $pattern"
}
/**
* [IgnoredReferenceMatcher] should be used to match references that cannot ever create leaks. The
* shortest path finder will never go through matching references.
* [IgnoredReferenceMatcher] 应该用于匹配永远不会造成泄漏的引用。
* 最短路径查找器永远不会通过匹配的引用。
*/
class IgnoredReferenceMatcher(override val pattern: ReferencePattern) : ReferenceMatcher() {
override fun toString() = "ignored ref: $pattern"
}
12.KeyedWeakReferenceFinder查找所有的KeyedWeakReference对应的id
/**
* Finds all objects tracked by a KeyedWeakReference, ie all objects that were passed to
* ObjectWatcher.watch.
* 查找所有的KeyedWeakReference对应的id
*/
object KeyedWeakReferenceFinder : LeakingObjectFinder {
override fun findLeakingObjectIds(graph: HeapGraph): Set<Long> =
findKeyedWeakReferences(graph)
.filter { it.hasReferent && it.isRetained }
//hasReferent对象存在,并且保留了一段时间
//isRetained保持; 持有; 保留; 继续拥有;
.map { it.referent.value }
.toSet()
//获取heap dump的时间
fun heapDumpUptimeMillis(graph: HeapGraph): Long? {
return graph.context.getOrPut("heapDumpUptimeMillis") {
val keyedWeakReferenceClass = graph.findClassByName("leakcanary.KeyedWeakReference")
val heapDumpUptimeMillis = if (keyedWeakReferenceClass == null) {
null
} else {
keyedWeakReferenceClass["heapDumpUptimeMillis"]?.value?.asLong
}
if (heapDumpUptimeMillis == null) {
SharkLog.d {
"leakcanary.KeyedWeakReference.heapDumpUptimeMillis field not found"
}
}
heapDumpUptimeMillis
}
}
internal fun findKeyedWeakReferences(graph: HeapGraph): List<KeyedWeakReferenceMirror> {
return graph.context.getOrPut(KEYED_WEAK_REFERENCE.name) {//todo 这里为什么getOrPut
val keyedWeakReferenceClass = graph.findClassByName("leakcanary.KeyedWeakReference")
val keyedWeakReferenceClassId = keyedWeakReferenceClass?.objectId ?: 0
val legacyKeyedWeakReferenceClassId =
graph.findClassByName("com.squareup.leakcanary.KeyedWeakReference")?.objectId ?: 0
val heapDumpUptimeMillis = heapDumpUptimeMillis(graph)
val addedToContext: List<KeyedWeakReferenceMirror> = graph.instances
.filter { instance ->
//过滤所有的instance,找到leakcanary.KeyedWeakReference或者com.squareup.leakcanary.KeyedWeakReference的对象实例
instance.instanceClassId == keyedWeakReferenceClassId || instance.instanceClassId == legacyKeyedWeakReferenceClassId
}
.map {
//封装为KeyedWeakReferenceMirror
KeyedWeakReferenceMirror.fromInstance(
it, heapDumpUptimeMillis
)
}
.toList()
graph.context[KEYED_WEAK_REFERENCE.name] = addedToContext
addedToContext
}
}
}
13.ReferencePattern将匹配给定 [ReferenceMatcher] 的引用的模式
/**
* A pattern that will match references for a given [ReferenceMatcher].
* 将匹配给定 [ReferenceMatcher] 的引用的模式。
*/
sealed class ReferencePattern : Serializable {
/**
* Matches local references held in the stack of frames of a given thread, identified by its name.
* 匹配保存在给定线程的帧堆栈中的本地引用,由其名称标识。
*/
data class JavaLocalPattern(
val threadName: String
) : ReferencePattern() {
override fun toString() = "local variable on thread $threadName"
companion object {
private const val serialVersionUID: Long = -8985446122829543654
}
}
/**
* Matches static field references, identified by [className] and [fieldName].
* 匹配由 [className] 和 [fieldName] 标识的静态字段引用。
*/
data class StaticFieldPattern(
val className: String,
val fieldName: String
) : ReferencePattern() {
override fun toString() = "static field $className#$fieldName"
companion object {
private const val serialVersionUID: Long = 7656908128775899611
}
}
/**
* Matches instances field references, identified by [className] and [fieldName].
* 匹配实例字段引用,由 [className] 和 [fieldName] 标识。
*
* Note: If [fieldName] is declared in a superclass it will still match for subclasses.
* This is to support overriding of rules for specific cases. If two [ReferenceMatcher] match for
* the same [fieldName] but for different [className] in a class hierarchy, then the closest
* class in the hierarchy wins.
* 注意:如果 [fieldName] 在超类中声明,它仍然会匹配子类。
* 这是为了支持在特定情况下覆盖规则。 如果两个 [ReferenceMatcher] 匹配同一个 [fieldName]
* 但对于类层次结构中的不同 [className],则层次结构中最接近的类获胜。
*/
data class InstanceFieldPattern(
val className: String,
val fieldName: String
) : ReferencePattern() {
override fun toString() = "instance field $className#$fieldName"
companion object {
private const val serialVersionUID: Long = 6649791455204159802
}
}
/**
* Matches native global variables (also known as jni global gc roots) that reference
* Java objects. The class name will match against classes, instances and object arrays with
* a matching class name.
* 匹配引用 Java 对象的本地全局变量(也称为 jni 全局 gc 根)。
* 类名将与具有匹配类名的类、实例和对象数组相匹配。
* todo ??
*/
data class NativeGlobalVariablePattern(val className: String) : ReferencePattern() {
override fun toString() = "native global variable referencing $className"
companion object {
private const val serialVersionUID: Long = -2651328076202244933
}
}
companion object {
private const val serialVersionUID: Long = -5113635523713591133
}
}
14.LeakTraceObject 代表泄漏的对象
data class LeakTraceObject(
val type: ObjectType,
/**
* Class name of the object.
* The class name format is the same as what would be returned by [Class.getName].
* 对象的类名。类名格式和[Class.getName]返回的一样。
*/
val className: String,
/**
* Labels that were computed during analysis. A label provides extra information that helps
* understand the state of the leak trace object.
* 在分析期间计算的标签。 标签提供了有助于了解泄漏跟踪对象状态的额外信息。
*/
val labels: Set<String>,
val leakingStatus: LeakingStatus,
val leakingStatusReason: String,
/**
* The minimum number of bytes which would be freed if all references to this object were
* released. Not null only if the retained heap size was computed AND [leakingStatus] is
* equal to [LeakingStatus.UNKNOWN] or [LeakingStatus.LEAKING].
* 如果对该对象的所有引用都被释放,则将被释放的最小字节数。
* 仅当计算保留堆大小且 [leakingStatus] 等于 [LeakingStatus.UNKNOWN] 或 [LeakingStatus.LEAKING] 时才不为 null。
*/
val retainedHeapByteSize: Int?,
/**
* The minimum number of objects which would be unreachable if all references to this object were
* released. Not null only if the retained heap size was computed AND [leakingStatus] is
* equal to [LeakingStatus.UNKNOWN] or [LeakingStatus.LEAKING].
*
* 如果对该对象的所有引用都被释放,则无法访问的最小对象数。
* 仅当计算保留堆大小且 [leakingStatus] 等于 [LeakingStatus.UNKNOWN] 或 [LeakingStatus.LEAKING] 时才不为 null。
*/
val retainedObjectCount: Int?
) : Serializable {
/**
* Returns {@link #className} without the package, ie stripped of any string content before the
* last period (included).
*/
val classSimpleName: String get() = className.lastSegment('.')
val typeName
get() = type.name.toLowerCase(Locale.US)
override fun toString(): String {
val firstLinePrefix = ""
val additionalLinesPrefix = "$ZERO_WIDTH_SPACE "
return toString(firstLinePrefix, additionalLinesPrefix, true)
}
internal fun toString(
firstLinePrefix: String,
additionalLinesPrefix: String,
showLeakingStatus: Boolean,
typeName: String = this.typeName
): String {
val leakStatus = when (leakingStatus) {
UNKNOWN -> "UNKNOWN"
NOT_LEAKING -> "NO ($leakingStatusReason)"
LEAKING -> "YES ($leakingStatusReason)"
}
var result = ""
result += "$firstLinePrefix$className $typeName"
if (showLeakingStatus) {
result += "\n${additionalLinesPrefix}Leaking: $leakStatus"
}
if (retainedHeapByteSize != null) {
val humanReadableRetainedHeapSize =
humanReadableByteCount(retainedHeapByteSize.toLong())
result += "\n${additionalLinesPrefix}Retaining $humanReadableRetainedHeapSize in $retainedObjectCount objects"
}
for (label in labels) {
result += "\n${additionalLinesPrefix}$label"
}
return result
}
enum class ObjectType {
CLASS,
ARRAY,
INSTANCE
}
enum class LeakingStatus {
/** The object was needed and therefore expected to be reachable.
* 该对象是需要的,因此预计是可达的。 */
NOT_LEAKING,
/** The object was no longer needed and therefore expected to be unreachable.
* 不再需要该对象,因此预计将无法访问该对象。 */
LEAKING,
/** No decision can be made about the provided object. */
UNKNOWN;
}
companion object {
private const val serialVersionUID = -3616216391305196341L
// https://stackoverflow.com/a/3758880
//将bytes long型转为可读的B,kB,MB,GB
private fun humanReadableByteCount(bytes: Long): String {
val unit = 1000
if (bytes < unit) return "$bytes B"
val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
val pre = "kMGTPE"[exp - 1]
return String.format("%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
}
}
}