memleak fix hopefully

This commit is contained in:
2025-07-26 12:25:55 -07:00
parent 463f881eaf
commit ccc68a3895

View File

@@ -12,6 +12,7 @@ import subprocess
import gc import gc
import psutil import psutil
import os import os
import sys
from .config import VR180Config from .config import VR180Config
from .detector import YOLODetector from .detector import YOLODetector
@@ -131,6 +132,15 @@ class VideoProcessor:
except ImportError: except ImportError:
pass pass
# Force Linux to release memory back to OS
if sys.platform == 'linux':
try:
import ctypes
libc = ctypes.CDLL("libc.so.6")
libc.malloc_trim(0)
except Exception as e:
print(f" Warning: Could not trim memory: {e}")
# Brief pause to allow cleanup # Brief pause to allow cleanup
time.sleep(0.1) time.sleep(0.1)
@@ -565,13 +575,15 @@ class VideoProcessor:
chunk_size, overlap_frames = self.calculate_optimal_chunking() chunk_size, overlap_frames = self.calculate_optimal_chunking()
# Process video in chunks # Process video in chunks
chunk_results = [] chunk_files = [] # Store file paths instead of frame data
temp_chunk_dir = Path(tempfile.mkdtemp(prefix="vr180_chunks_"))
try:
for start_frame in range(0, self.total_frames, chunk_size - overlap_frames): for start_frame in range(0, self.total_frames, chunk_size - overlap_frames):
end_frame = min(start_frame + chunk_size, self.total_frames) end_frame = min(start_frame + chunk_size, self.total_frames)
frames_to_read = end_frame - start_frame frames_to_read = end_frame - start_frame
chunk_idx = len(chunk_results) chunk_idx = len(chunk_files)
print(f"\nProcessing chunk {chunk_idx}: frames {start_frame}-{end_frame}") print(f"\nProcessing chunk {chunk_idx}: frames {start_frame}-{end_frame}")
# Read chunk frames # Read chunk frames
@@ -584,22 +596,46 @@ class VideoProcessor:
# Process chunk # Process chunk
matted_frames = self.process_chunk(frames, chunk_idx) matted_frames = self.process_chunk(frames, chunk_idx)
chunk_results.append(matted_frames)
# Save chunk to disk immediately to free memory
chunk_path = temp_chunk_dir / f"chunk_{chunk_idx:04d}.npz"
print(f"Saving chunk {chunk_idx} to disk...")
np.savez_compressed(str(chunk_path), frames=matted_frames)
chunk_files.append(chunk_path)
# Free the frames from memory immediately
del matted_frames
del frames
# Update statistics # Update statistics
self.processing_stats['chunks_processed'] += 1 self.processing_stats['chunks_processed'] += 1
self.processing_stats['frames_processed'] += len(frames) self.processing_stats['frames_processed'] += frames_to_read
# Memory cleanup # Aggressive memory cleanup after each chunk
self._aggressive_memory_cleanup(f"chunk {chunk_idx} completion")
# Also use memory manager cleanup
self.memory_manager.cleanup_memory() self.memory_manager.cleanup_memory()
if self.memory_manager.should_emergency_cleanup(): if self.memory_manager.should_emergency_cleanup():
self.memory_manager.emergency_cleanup() self.memory_manager.emergency_cleanup()
# Merge chunks if multiple # Load and merge chunks from disk
print("\nMerging chunks...") print("\nLoading and merging chunks...")
chunk_results = []
for chunk_file in chunk_files:
print(f"Loading {chunk_file.name}...")
chunk_data = np.load(str(chunk_file))
chunk_results.append(chunk_data['frames'])
chunk_data.close() # Close the file
# Merge chunks
final_frames = self.merge_overlapping_chunks(chunk_results, overlap_frames) final_frames = self.merge_overlapping_chunks(chunk_results, overlap_frames)
# Free chunk results after merging
del chunk_results
self._aggressive_memory_cleanup("after merging chunks")
# Save results # Save results
print(f"Saving {len(final_frames)} processed frames...") print(f"Saving {len(final_frames)} processed frames...")
self.save_video(final_frames, self.config.output.path) self.save_video(final_frames, self.config.output.path)
@@ -618,6 +654,12 @@ class VideoProcessor:
print("Video processing completed!") print("Video processing completed!")
finally:
# Clean up temporary chunk files
if temp_chunk_dir.exists():
print("Cleaning up temporary chunk files...")
shutil.rmtree(temp_chunk_dir)
def _print_processing_statistics(self): def _print_processing_statistics(self):
"""Print detailed processing statistics""" """Print detailed processing statistics"""
stats = self.processing_stats stats = self.processing_stats