Tencent/matrix · error · FileNotFoundException

free space($freeSpace) less than $CLEAN_THRESHOLD, skip…

Error message

free space($freeSpace) less than $CLEAN_THRESHOLD, skip dump hprof

What it means

Matrix ResourceCanary's HprofFileManager.makeSureEnoughSpace() verifies the hprof output directory has enough free disk space before dumping the heap. If free space is below the required threshold (CLEAN_THRESHOLD, or MIN_FREE_SPACE when deleteSoon is set), it first LRU-cleans old hprof files and then aborts the dump by throwing FileNotFoundException with this message. It is a deliberate guard to avoid filling the device disk with a multi-hundred-MB hprof file.

Solutions

  1. Free device storage (uninstall apps, clear caches) so free space exceeds CLEAN_THRESHOLD, then retry the leak dump
  2. Lower the CLEAN_THRESHOLD / MIN_FREE_SPACE configuration to match your test device's capacity
  3. Clear Matrix's own hprof directory (the LRU cleanup target) before triggering the dump
  4. Run the leak test on a device/emulator with a larger data partition or expand emulator disk size

Example fix

// before
Matrix.Builder().plugin(ResourcePlugin(ResourceConfig.Builder().setHprofCleanThreshold(200 * 1024 * 1024).build()))
// after
Matrix.Builder().plugin(ResourcePlugin(ResourceConfig.Builder().setHprofCleanThreshold(50 * 1024 * 1024).build())) // fits small test device
Defensive patterns

Strategy: try-catch

Validate before calling

// Kotlin: check free space before triggering a leak dump
val dir = File(matrixHprofDir)
val freeBytes = dir.usableSpace
if (freeBytes < CLEAN_THRESHOLD) {
    dir.listFiles()?.forEach { it.delete() } // LRU-clean old hprofs first
    if (dir.usableSpace < MIN_FREE_SPACE) {
        // skip dump / alert: not enough space
    }
}

Try / catch

try {
    hprofFileManager.makeSureEnoughSpace(deleteSoon = false)
    // proceed with dump
} catch (e: FileNotFoundException) {
    Log.w("Matrix", "Skipped hprof dump: insufficient free space", e)
    // report to monitoring, free storage, or retry later
}

Prevention

When it happens

Trigger: Calling prepare()/makeSureEnoughSpace() when File.getUsableSpace() on the hprof directory returns less than CLEAN_THRESHOLD (or less than MIN_FREE_SPACE when deleteSoon=true), so dumping hprof is skipped. Happens after LRU cleanup fails to reclaim enough space.

Common situations: Low-end devices or emulators with a nearly full data partition; app cache dir crowded by other data so even after deleting old hprofs the threshold is not met; CLEAN_THRESHOLD configured too high for small test devices; repeated memory-leak tests that accumulate hprof files faster than cleanup.

Related errors


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

Appendix: source

Thrown at matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/dumper/HprofFileManager.kt:80

    private fun File.reserve() {
        if (!exists() && (!mkdirs() || !canWrite())) {
            "fialed to create new hprof file since path: $absolutePath is not writable".let {
                MatrixLog.e(TAG, it)
                throw FileNotFoundException(it)
            }
        }
    }

    private fun File.makeSureEnoughSpace(deleteSoon: Boolean) {
        if (!isDirectory) {
            return
        }
        lru()
        if (freeSpace < CLEAN_THRESHOLD) {
            listFiles()?.forEach { it.delete() }
        }
        if (freeSpace < if (deleteSoon) MIN_FREE_SPACE else CLEAN_THRESHOLD) {
            throw FileNotFoundException("free space($freeSpace) less than $CLEAN_THRESHOLD, skip dump hprof")
        }
    }

    private fun File.lru() {
        if (!isDirectory) {
            return
        }
        val files = listFiles() ?: return
        files.sortBy { it.lastModified() }
        files.forEach {
            MatrixLog.d(TAG, "==> list sorted: ${it.absolutePath}, last mod = ${it.lastModified()}")
        }
        if (files.size >= MAX_FILE_COUNT) {
            files.take(files.size - MAX_FILE_COUNT + 1).forEach {
                it.delete()
            }
        }
    }

View on GitHub (pinned to 3b8293bd65)