Browse Source
- Create MatUtils.kt with safe resource management patterns - Fix major Mat leak in ScreenCaptureService.kt image processing pipeline - Fix Mat leaks in EnhancedOCR.kt enhanceImageForOCR() and upscaleImage() - Add Mat.use() extension for automatic cleanup with try-finally - Add useMats() utility for multi-Mat operations - Add releaseSafely() for batch Mat cleanup with error handling Critical stability fix: prevents native memory leaks that cause app crashes during extended detection use. Mat objects now guaranteed to be released even in exception paths. Related: REFACTORING_TASKS.md CRITICAL-001 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>fix/critical-001-opencv-mat-memory-leaks
3 changed files with 194 additions and 58 deletions
@ -0,0 +1,124 @@ |
|||||
|
package com.quillstudios.pokegoalshelper.utils |
||||
|
|
||||
|
import org.opencv.core.Mat |
||||
|
import android.util.Log |
||||
|
|
||||
|
/** |
||||
|
* OpenCV Mat resource management utilities to prevent native memory leaks. |
||||
|
* |
||||
|
* Mat objects hold native memory that must be explicitly released to avoid memory leaks. |
||||
|
* These utilities provide safe patterns for Mat lifecycle management. |
||||
|
*/ |
||||
|
object MatUtils { |
||||
|
private const val TAG = "MatUtils" |
||||
|
|
||||
|
/** |
||||
|
* Execute a block with a Mat resource, ensuring it's properly released. |
||||
|
* |
||||
|
* Usage: |
||||
|
* ```kotlin |
||||
|
* val result = Mat().use { mat -> |
||||
|
* // Use mat safely |
||||
|
* processImage(mat) |
||||
|
* return@use someResult |
||||
|
* } |
||||
|
* ``` |
||||
|
*/ |
||||
|
fun <T> Mat.use(block: (Mat) -> T): T { |
||||
|
try { |
||||
|
return block(this) |
||||
|
} finally { |
||||
|
try { |
||||
|
this.release() |
||||
|
} catch (e: Exception) { |
||||
|
Log.w(TAG, "Warning: Error releasing Mat", e) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Execute a block with multiple Mat resources, ensuring all are properly released. |
||||
|
* |
||||
|
* Usage: |
||||
|
* ```kotlin |
||||
|
* val result = useMats(Mat(), Mat()) { mat1, mat2 -> |
||||
|
* // Use mats safely |
||||
|
* processImages(mat1, mat2) |
||||
|
* return@useMats someResult |
||||
|
* } |
||||
|
* ``` |
||||
|
*/ |
||||
|
fun <T> useMats(mat1: Mat, mat2: Mat, block: (Mat, Mat) -> T): T { |
||||
|
try { |
||||
|
return block(mat1, mat2) |
||||
|
} finally { |
||||
|
releaseSafely(mat1, mat2) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Execute a block with three Mat resources. |
||||
|
*/ |
||||
|
fun <T> useMats(mat1: Mat, mat2: Mat, mat3: Mat, block: (Mat, Mat, Mat) -> T): T { |
||||
|
try { |
||||
|
return block(mat1, mat2, mat3) |
||||
|
} finally { |
||||
|
releaseSafely(mat1, mat2, mat3) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Safely release multiple Mat objects, logging any errors. |
||||
|
*/ |
||||
|
fun releaseSafely(vararg mats: Mat) { |
||||
|
for (mat in mats) { |
||||
|
try { |
||||
|
mat.release() |
||||
|
} catch (e: Exception) { |
||||
|
Log.w(TAG, "Warning: Error releasing Mat", e) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Create a Mat with automatic resource management. |
||||
|
* |
||||
|
* Usage: |
||||
|
* ```kotlin |
||||
|
* val result = createMat { mat -> |
||||
|
* // mat is automatically released |
||||
|
* Utils.bitmapToMat(bitmap, mat) |
||||
|
* processImage(mat) |
||||
|
* } |
||||
|
* ``` |
||||
|
*/ |
||||
|
fun <T> createMat(block: (Mat) -> T): T { |
||||
|
return Mat().use(block) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Copy a Mat safely with automatic cleanup. |
||||
|
*/ |
||||
|
fun Mat.safeCopy(): Mat { |
||||
|
val copy = Mat() |
||||
|
try { |
||||
|
this.copyTo(copy) |
||||
|
return copy |
||||
|
} catch (e: Exception) { |
||||
|
copy.release() |
||||
|
throw e |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Debug helper to track Mat memory usage. |
||||
|
*/ |
||||
|
fun logMatInfo(mat: Mat, label: String) { |
||||
|
try { |
||||
|
val bytes = mat.total() * mat.elemSize() |
||||
|
Log.d(TAG, "$label: Mat ${mat.cols()}x${mat.rows()}, ${mat.channels()} channels, ${bytes} bytes") |
||||
|
} catch (e: Exception) { |
||||
|
Log.d(TAG, "$label: Mat is empty or invalid") |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue