Created
June 5, 2024 13:58
-
-
Save fourlastor/23602bb72a7e2781dc88cd05dfe14281 to your computer and use it in GitHub Desktop.
leak canary JVM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dependencies { | |
implementation("com.squareup.leakcanary:leakcanary-object-watcher-android-support-fragments:2.12") | |
implementation("com.squareup.leakcanary:shark:2.12") | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.sun.management.HotSpotDiagnosticMXBean | |
import java.lang.management.ManagementFactory | |
object HotSpotHeapDumper { | |
private val mBean: HotSpotDiagnosticMXBean by lazy { | |
val server = ManagementFactory.getPlatformMBeanServer() | |
ManagementFactory.newPlatformMXBeanProxy( | |
server, | |
"com.sun.management:type=HotSpotDiagnostic", | |
HotSpotDiagnosticMXBean::class.java | |
) | |
} | |
fun dumpHeap(fileName: String) { | |
mBean.dumpHeap(fileName, LIVE) | |
} | |
private const val LIVE = true | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import leakcanary.GcTrigger | |
import leakcanary.ObjectWatcher | |
import leakcanary.OnObjectRetainedListener | |
import shark.HeapAnalyzer | |
import shark.KeyedWeakReferenceFinder | |
import shark.ObjectInspectors | |
import shark.OnAnalysisProgressListener | |
import java.io.File | |
import java.text.SimpleDateFormat | |
import java.util.Date | |
import java.util.Locale.US | |
class JvmHeapAnalyzer(private val objectWatcher: ObjectWatcher) : | |
OnObjectRetainedListener { | |
private val fileNameFormat = SimpleDateFormat(DATE_PATTERN, US) | |
override fun onObjectRetained() { | |
GcTrigger.Default.runGc() | |
if (objectWatcher.retainedObjectCount == 0) { | |
return | |
} | |
val fileName = fileNameFormat.format(Date()) | |
val hprofFile = File(fileName) | |
println("Dumping the heap to ${hprofFile.absolutePath}") | |
HotSpotHeapDumper.dumpHeap(hprofFile.absolutePath) | |
val analyzer = HeapAnalyzer( | |
OnAnalysisProgressListener { step -> | |
println("Analysis in progress, working on: ${step.name}") | |
}) | |
val heapDumpAnalysis = analyzer.analyze( | |
heapDumpFile = hprofFile, | |
leakingObjectFinder = KeyedWeakReferenceFinder, | |
computeRetainedHeapSize = true, | |
objectInspectors = ObjectInspectors.jdkDefaults | |
) | |
println(heapDumpAnalysis) | |
} | |
companion object { | |
private const val DATE_PATTERN = "yyyy-MM-dd_HH-mm-ss_SSS'.hprof'" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class JvmLeakTracer : LeakTracer { | |
private val scheduledExecutor = Executors.newSingleThreadScheduledExecutor() | |
private val objectWatcher = ObjectWatcher( | |
clock = { System.currentTimeMillis() }, | |
checkRetainedExecutor = { command -> scheduledExecutor.schedule(command, 5, TimeUnit.SECONDS) } | |
).apply { | |
addOnObjectRetainedListener(JvmHeapAnalyzer(this)) | |
} | |
override fun expectWeaklyReachable(watchedObject: Any, description: String) { | |
objectWatcher.expectWeaklyReachable(watchedObject, description) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** Memory leak tracer. */ | |
interface LeakTracer { | |
/** Call this method when you expect [watchedObject] to be released from memory. */ | |
fun expectWeaklyReachable(watchedObject: Any, description: String) | |
object NoOp : LeakTracer { | |
override fun expectWeaklyReachable(watchedObject: Any, description: String) = Unit | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment