Skip to content

Commit 2ec8bfb

Browse files
authored
Fix potential memory leaks (meta-pytorch#208)
* Update BirdDetectionPipeline.java * Add cleanup methods for detection pipeline
1 parent 08fc9e4 commit 2ec8bfb

2 files changed

Lines changed: 143 additions & 58 deletions

File tree

Yolo/android/app/src/main/java/com/example/executorchyolodemo/BirdDetectionActivity.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,30 @@ protected void onCreate(Bundle savedInstanceState) {
9797
}
9898
}
9999

100+
@Override
101+
protected void onDestroy() {
102+
super.onDestroy();
103+
104+
// Clean up the detection pipeline
105+
if (detectionPipeline != null) {
106+
detectionPipeline.close();
107+
detectionPipeline = null;
108+
}
109+
110+
Log.d(TAG, "BirdDetectionActivity destroyed");
111+
}
112+
113+
@Override
114+
protected void onPause() {
115+
super.onPause();
116+
117+
// Optional: Release resources when app goes to background
118+
if (detectionPipeline != null) {
119+
detectionPipeline.close();
120+
detectionPipeline = null;
121+
}
122+
}
123+
100124
private void initializeViews() {
101125
previewView = findViewById(R.id.previewView);
102126
overlayImageView = findViewById(R.id.overlayImageView);
@@ -432,4 +456,4 @@ protected void onResume() {
432456
super.onResume();
433457
updateSessionUI();
434458
}
435-
}
459+
}

Yolo/android/app/src/main/java/com/example/executorchyolodemo/BirdDetectionPipeline.java

Lines changed: 118 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -154,87 +154,115 @@ private void loadBirdSpeciesNames(Context context) throws IOException {
154154
public List<BirdDetection> detectBirds(Bitmap bitmap) {
155155
List<BirdDetection> results = new ArrayList<>();
156156
frameCounter++;
157-
157+
158+
Tensor yoloInput = null;
159+
EValue[] yoloOutputs = null;
160+
158161
try {
159162
// Cleanup old detection history every 30 frames
160163
if (frameCounter % 30 == 0) {
161164
cleanupOldDetections();
162165
}
163-
164-
Tensor yoloInput = preprocessForYolo(bitmap);
166+
167+
yoloInput = preprocessForYolo(bitmap);
165168
if (yoloInput == null) {
166169
return results;
167170
}
168-
169-
EValue[] yoloOutputs = yoloModule.forward(EValue.from(yoloInput));
171+
172+
yoloOutputs = yoloModule.forward(EValue.from(yoloInput));
170173
if (yoloOutputs == null || yoloOutputs.length == 0) {
171174
return results;
172175
}
173-
176+
174177
List<Detection> detections = parseYoloV8OutputOptimized(yoloOutputs, bitmap.getWidth(), bitmap.getHeight());
175-
178+
176179
if (DEBUG_OUTPUT) {
177180
Log.d(TAG, "Raw detections before NMS: " + detections.size());
178181
}
179-
182+
180183
// Apply enhanced NMS
181-
List<Detection> filteredDetections = applyEnhancedNMS(detections);
182-
184+
List<Detection> nmsDetections = applyEnhancedNMS(detections);
185+
183186
if (DEBUG_OUTPUT) {
184-
Log.d(TAG, "Detections after enhanced NMS: " + filteredDetections.size());
187+
Log.d(TAG, "Detections after NMS: " + nmsDetections.size());
185188
}
186-
187-
// Apply temporal stability tracking
188-
List<Detection> stableDetections = applyTemporalStabilityTracking(filteredDetections);
189-
190-
// Limit to MAX_DETECTIONS with quality ranking
191-
if (stableDetections.size() > MAX_DETECTIONS) {
192-
// Sort by confidence and take top detections
193-
Collections.sort(stableDetections, (a, b) -> Float.compare(b.confidence, a.confidence));
194-
stableDetections = stableDetections.subList(0, MAX_DETECTIONS);
195-
}
196-
197-
// Process stable detections only
198-
for (Detection detection : stableDetections) {
189+
190+
// Classify each detection
191+
for (Detection detection : nmsDetections) {
199192
try {
200-
if (validateBirdDetectionEnhanced(bitmap, detection.boundingBox)) {
201-
String[] speciesResult = classifyBird(bitmap, detection.boundingBox);
202-
float classifierConfidence = Float.parseFloat(speciesResult[1]);
203-
204-
// Stricter classifier requirement for false positive reduction
205-
if (classifierConfidence > 0.5f) {
206-
// Weighted average favoring detection confidence
207-
float finalConfidence = (detection.confidence * 0.8f + classifierConfidence * 0.2f);
208-
209-
// Check if this detection is stable over time
210-
DetectionHistory history = detectionHistory.get(detection.locationKey);
211-
boolean isStable = history != null && history.isStable();
212-
213-
results.add(new BirdDetection(
214-
detection.boundingBox,
215-
speciesResult[0],
216-
finalConfidence,
217-
isStable
218-
));
219-
220-
if (DEBUG_OUTPUT) {
221-
Log.d(TAG, "FINAL BIRD: " + speciesResult[0] + " conf=" + finalConfidence + " stable=" + isStable);
222-
}
223-
}
193+
Bitmap croppedBird = cropBitmap(bitmap, detection.boundingBox);
194+
if (croppedBird == null) continue;
195+
196+
String species = classifyBird(croppedBird);
197+
198+
// Recycle the cropped bitmap immediately after classification
199+
if (!croppedBird.isRecycled()) {
200+
croppedBird.recycle();
201+
}
202+
203+
// Update detection history
204+
DetectionHistory history = detectionHistory.get(detection.locationKey);
205+
if (history == null) {
206+
history = new DetectionHistory();
207+
detectionHistory.put(detection.locationKey, history);
208+
}
209+
history.addConfidence(detection.confidence);
210+
211+
// Apply temporal bonus for stable detections
212+
float finalConfidence = detection.confidence;
213+
if (history.isStable()) {
214+
finalConfidence = Math.min(1.0f, detection.confidence + TEMPORAL_BONUS);
215+
}
216+
217+
BirdDetection birdDetection = new BirdDetection(
218+
detection.boundingBox,
219+
species,
220+
finalConfidence,
221+
history.isStable()
222+
);
223+
results.add(birdDetection);
224+
225+
if (DEBUG_OUTPUT) {
226+
Log.d(TAG, String.format("Bird detected: %s (%.2f) at [%.0f,%.0f,%.0f,%.0f] stable=%b",
227+
species, finalConfidence,
228+
detection.boundingBox.left, detection.boundingBox.top,
229+
detection.boundingBox.right, detection.boundingBox.bottom,
230+
history.isStable()));
224231
}
225232
} catch (Exception e) {
226-
Log.e(TAG, "Failed to classify detection", e);
233+
Log.e(TAG, "Error classifying detection", e);
227234
}
228235
}
229-
236+
237+
if (DEBUG_OUTPUT) {
238+
Log.d(TAG, "Final bird detections: " + results.size());
239+
}
240+
230241
} catch (Exception e) {
231-
Log.e(TAG, "Bird detection failed", e);
232-
}
233-
234-
if (DEBUG_OUTPUT) {
235-
Log.d(TAG, "TOTAL FINAL RESULTS: " + results.size());
242+
Log.e(TAG, "Error in detectBirds", e);
243+
} finally {
244+
// CRITICAL: Release tensors to prevent memory leak
245+
if (yoloInput != null) {
246+
try {
247+
yoloInput.close();
248+
} catch (Exception e) {
249+
Log.e(TAG, "Error closing yoloInput", e);
250+
}
251+
}
252+
253+
if (yoloOutputs != null) {
254+
for (EValue output : yoloOutputs) {
255+
if (output != null) {
256+
try {
257+
output.close();
258+
} catch (Exception e) {
259+
Log.e(TAG, "Error closing output", e);
260+
}
261+
}
262+
}
263+
}
236264
}
237-
265+
238266
return results;
239267
}
240268

@@ -315,6 +343,39 @@ private void cleanupOldDetections() {
315343
}
316344
}
317345

346+
/**
347+
* Release all resources and destroy models.
348+
* Call this when the pipeline is no longer needed.
349+
*/
350+
public void close() {
351+
Log.d(TAG, "Closing BirdDetectionPipeline and releasing resources");
352+
353+
try {
354+
if (yoloModule != null) {
355+
yoloModule.destroy();
356+
yoloModule = null;
357+
}
358+
} catch (Exception e) {
359+
Log.e(TAG, "Error destroying yoloModule", e);
360+
}
361+
362+
try {
363+
if (classifierModule != null) {
364+
classifierModule.destroy();
365+
classifierModule = null;
366+
}
367+
} catch (Exception e) {
368+
Log.e(TAG, "Error destroying classifierModule", e);
369+
}
370+
371+
// Clear detection history
372+
if (detectionHistory != null) {
373+
detectionHistory.clear();
374+
}
375+
376+
Log.d(TAG, "BirdDetectionPipeline closed successfully");
377+
}
378+
318379
private Tensor preprocessForYolo(Bitmap bitmap) {
319380
try {
320381
if (bitmap == null || bitmap.isRecycled()) {
@@ -595,4 +656,4 @@ private Bitmap cropBitmap(Bitmap bitmap, RectF box) {
595656
public void cleanup() {
596657
detectionHistory.clear();
597658
}
598-
}
659+
}

0 commit comments

Comments
 (0)