leak_graph 0.3.0
leak_graph: ^0.3.0 copied to clipboard
Pure-Dart library for loading VM heap snapshots and analysing object retaining paths to surface memory leaks.
0.3.0 #
- Owner attribution (behavior change). Each leak candidate is now
attributed to the DEEPEST app-owned object on its retaining path (walk
leaf→root, first app hop = the anchor). A cluster HEADLINES and DEDUPES by
that owner, so N internal SDK leaves retained by one app object fold into a
single
_LeakyScreenState ×Nfinding instead of several SDK-named clusters (classNameis now the owner's;instanceCountcounts distinct owners). The cluster signature is anchored at the owner (root→anchor), so same-owner records group regardless of which leaf BFS reached first. Cluster identity therefore changes for every app-anchored cluster versus 0.2.2 — a baseline or export written by an older version is NOT signature-comparable, and will read every app-anchored cluster as NEW/GONE churn. Re-baseline against 0.3.0. The internal leaf + root stay onrepresentativePathfor drill-down. (The live-tree pass also now suppresses only candidates whose root is not leak-prone, so a leak-prone-rooted object reached from a live anchor via a stale edge is no longer wrongly hidden.) ClassOrigin— classifies a class's declaring library asproject,dependency,flutterFramework,dartSdk, orunknown. NewOriginClassifierdoes the classification given a resolved project-package set;kFlutterFrameworkPackageslists the recognised framework packages.GraphHop.libraryUri— thepackage:/dart:library that declared a hop's class, carried through JSON for attribution rendering. Deliberately excluded from==/hashCode— that field alone does not affectGraphHop/GraphRetainingPathequality. (Signature identity still changes in 0.3.0, but via the owner-anchoredpathSignatureabove, not this field.)GraphLeakCluster.anchorHopIndex/leafClassName— names the path hop and internal leaf class an app-code anchor attributes a leak to, when one exists.PackageRollupandGraphAnalysisResult.anchorRollups/.declaredRollups— per-package aggregation of a run's reported leaks, keyed by the package that retains vs. the package that declares each leaked class.AppPackageSourcelabels which detection path (explicit config, auto-detected, or disabled) produced the app-package set an analysis used, so a rollup is never presented as more precise than it is.GraphAnalysisResult.resolvedAppPackagesreports that resolved set.appPackagestakes BARE package names (my_app), not library URIs; an entry containing://matches nothing and now surfaces astats.warningsentry.GraphAnalysisResult.schemaVersionbumped to 2; an export without the key is still read as version 1.- CLI baseline/gate:
analyzeanddiffgrew a baseline in/out module, byte-absolute threshold flags, and a verdict gate over the initiative-wide exit contract (0 ok / 1 usage / 2 tool failure / 3 gate failed), with--format md|github|jsonrenderers and NEW-vs-KNOWN classification by signature.diffis exposed as theleak_diffexecutable (namespaced off the systemdiff(1)). package:leak_graph/io.dart— a new, additivedart:io-backed entrypoint (the mainleak_graph.dartbarrel stays pure Dart).projectPackagesFromDirdetects the app's own workspace/melos member package names from a project directory, for feeding an explicitappPackagesconfig instead of relying on auto-detection;packageNameFromPubspecis the pure pubspec-name parser behind it.
0.2.2 #
GraphAnalysisResult.classPathDistributions— per-class distribution of a class's instances across their distinct shortest retaining paths (grouped by path signature), materialised for a bounded set of classes. Backs a native-DevTools-style "N instances → X via path A, Y via path B…" breakdown. EachPathBucketcarries a representative path, instance count, and summed shallow bytes;ClassPathDistributionreportssampledInstancesvstotalInstancesso a capped (sampled) breakdown is never presented as complete. NewbuildClassPathDistributionsanalyzer pass andPathBucket/ClassPathDistributionmodels (JSON round-trip supported).
0.2.1 #
- Docs + packaging only (no library code change from 0.2.0): rewritten README
(standalone-first framing; documents
classRootProfiles, JSON round-trip, and the CLI) and expose theleak_capturecommand viaexecutables:. 0.2.0 shipped the same code but with a stale README and without the executable entry.
0.2.0 #
GraphAnalysisResult.classRootProfiles— aClassRootProfilefor EVERY class reachable from the GC root (not just leak-prone-rooted clusters), grouping each class's instances by theRootKindof their closest retaining root. Lets a UI separate live-UI-tree classes from leak-prone ones instead of only ever seeing leak candidates. A bounded subset of classes (the largest by instance count, plus any class with a leak-prone instance) also gets a representative shortest retaining path.toJson/fromJsononClassCount,GraphHop,GraphRetainingPath,GraphLeakCluster,GraphAnalysisStats,GraphAnalysisResult, and the newClassRootProfile— a full analysis run can now round-trip through JSON for snapshot export.computeDiff— diffs two class histograms into per-class instance/byte deltas (growth and shrinkage), backing snapshot-to-snapshot comparison.- Standalone heap-growth and retaining-path analysis directly from an on-device heap snapshot — no live VM-service connection required.
- Command-line heap dumper for capturing snapshots off a running app:
bin/capture.dart(run viadart run leak_graph:capture) — connects to a VM Service URI, streams a rawdartheapsnapshot to a file, and can optionally run the analysis in the same pass.tool/heapdump.sh— a standalone bash + adb + python3 dumper (no Dart toolchain) that discovers the VM Service URL from logcat, forwards the port, and streams the samedartheapfile straight off an Android device.
0.1.0 #
Initial release.
Pure-Dart heap-snapshot analysis: load a VM heap snapshot, build an object graph, and find the retaining paths that keep suspected leaks alive — with no dependency on a live VM-service connection.
heapGraphFromBytes/loadHeapGraph— parse a.dataheap snapshot (e.g. fromNativeRuntime.writeHeapSnapshotToFile) into aHeapGraphView. Never throws on malformed input; returns a sentinel graph instead.GraphLeakAnalyzer.analyze— the end-to-end pipeline: BFS shortest retaining paths, leak-prone root classification (timer / stream / closure / finalizer / static), app-relevance filtering, optional live-tree confirmation, and clustering by retaining-path signature. Each leak is attributed to the deepest app-owned object on its path, with the SDK chain kept as detail.retainingPathForClass(graph, className)— shortest retaining path to the first reachable instance of a class (standalone, no VM service).HeapGraphView.classHistogram()— per-class instance counts derived from the snapshot, for VM-service-free heap-growth detection.bin/analyze.dart— CLI that analyses a heap-snapshot file and renders a report.