Tencent/matrix · error · IllegalStateException

Unabled to find destroy activity info class with name:

Error message

Unabled to find destroy activity info class with name: 

What it means

ActivityLeakAnalyzer looks up the DestroyedActivityInfo class in the heap dump snapshot to find keyed references to destroyed activities. If that class is absent from the dump, the analyzer cannot locate leak candidates and throws IllegalStateException. This usually means the Matrix resource monitoring was not active at capture time, so no destroyed-activity info instances were ever created.

Solutions

  1. Ensure the ResourcePlugin is installed and has detected at least one destroyed activity before the hprof is taken.
  2. Check ProGuard/R8 keep rules so DestroyedActivityInfo is not renamed/stripped.
  3. Verify you are analyzing the hprof from the app process where the leak was suspected.
  4. Confirm DESTROYED_ACTIVITY_INFO_CLASSNAME matches the class actually present (no package relocation between versions).

Example fix

// before
final ClassObj infoClass = snapshot.findClass(DESTROYED_ACTIVITY_INFO_CLASSNAME);
if (infoClass == null) {
    throw new IllegalStateException("Unabled to find destroy activity info class with name: " + DESTROYED_ACTIVITY_INFO_CLASSNAME);
}
// after
final ClassObj infoClass = snapshot.findClass(DESTROYED_ACTIVITY_INFO_CLASSNAME);
if (infoClass == null) {
    return null; // no destroyed-activity info recorded; report 'no leak found'
}
Defensive patterns

Strategy: validation

Validate before calling

if (snapshot.findClass(DESTROYED_ACTIVITY_INFO_CLASSNAME) == null) { reportNoLeak("class absent from dump"); return; }

Try / catch

try { ref = findLeakingReference(key, snapshot); } catch (IllegalStateException e) { log.warn("no destroyed-activity info in dump", e); return ActivityLeakResult.noLeak(); }

Prevention

When it happens

Trigger: findLeakingReference runs snapshot.findClass(DESTROYED_ACTIVITY_INFO_CLASSNAME) and it returns null — the class was never loaded in the dumped process because the leak-monitor hook never recorded a destroyed activity, or the dump comes from a process where the class was stripped/renamed.

Common situations: Heap dumps captured before Matrix's ResourcePlugin initialized; dumps from builds without the resource-canary instrumentation; obfuscation (ProGuard/R8) renaming or removing DestroyedActivityInfo; analyzing a dump from the wrong process.

Related errors


AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08). Data as JSON: /api/errors/75856040be475b88. Report an issue: GitHub.

Appendix: source

Thrown at matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-analyzer/src/main/java/com/tencent/matrix/resource/analyzer/ActivityLeakAnalyzer.java:89

            final Snapshot snapshot = heapSnapshot.getSnapshot();
            final Instance leakingRef = findLeakingReference(refKey, snapshot);

            // False alarm, weak reference was cleared in between key check and heap dump.
            if (leakingRef == null) {
                return ActivityLeakResult.noLeak(AnalyzeUtil.since(analysisStartNanoTime));
            }

            return findLeakTrace(analysisStartNanoTime, snapshot, leakingRef);
        } catch (Throwable e) {
            e.printStackTrace();
            return ActivityLeakResult.failure(e, AnalyzeUtil.since(analysisStartNanoTime));
        }
    }

    private Instance findLeakingReference(String key, Snapshot snapshot) {
        final ClassObj infoClass = snapshot.findClass(DESTROYED_ACTIVITY_INFO_CLASSNAME);
        if (infoClass == null) {
            throw new IllegalStateException("Unabled to find destroy activity info class with name: "
                    + DESTROYED_ACTIVITY_INFO_CLASSNAME);
        }
        List<String> keysFound = new ArrayList<>();
        for (Instance infoInstance : infoClass.getInstancesList()) {
            final List<ClassInstance.FieldValue> values = classInstanceValues(infoInstance);
            final String keyCandidate = asString(fieldValue(values, ACTIVITY_REFERENCE_KEY_FIELDNAME));
            if (keyCandidate.equals(key)) {
                final Instance weakRefObj = fieldValue(values, ACTIVITY_REFERENCE_FIELDNAME);
                if (weakRefObj == null) {
                    continue;
                }
                final List<ClassInstance.FieldValue> activityRefs = classInstanceValues(weakRefObj);
                return fieldValue(activityRefs, "referent");
            }
            keysFound.add(keyCandidate);
        }
        throw new IllegalStateException(
                "Could not find weak reference with key " + key + " in " + keysFound);

View on GitHub (pinned to 3b8293bd65)