# How SmartTube Handles OutOfMemoryError Crashes: A Two-Layer Recovery System

> SmartTube prevents OutOfMemoryError crashes with a two-layer recovery system. It automatically downgrades components and reduces buffer sizes to keep the app running smoothly.

- Repository: [Yuriy L/SmartTube](https://github.com/yuliskov/SmartTube)
- Tags: internals
- Published: 2026-09-14

---

**SmartTube prevents app terminations from OutOfMemoryError exceptions by implementing both global and playback-level interceptors that automatically downgrade memory-intensive components, switching from OkHttp data sources to default implementations and reducing video buffer sizes when RAM pressure is detected.**

SmartTube's architecture specifically addresses memory constraints common to Android TV devices through a sophisticated error-handling strategy. Rather than allowing the application to crash when memory is exhausted, the codebase implements targeted recovery mechanisms in `MainApplication` and `ErrorFixerController`. These components work together to reduce memory footprint dynamically while preserving the current playback session when possible.

## Global Crash Filter: Preventive Memory Management

The first line of defense operates at the application level through `MainApplication.applyCrashFixes()`. Located at lines 88-100 in [`smarttubetv/src/main/java/com/liskovsoft/smartyoutubetv2/tv/ui/main/MainApplication.java`](https://github.com/yuliskov/SmartTube/blob/main/smarttubetv/src/main/java/com/liskovsoft/smartyoutubetv2/tv/ui/main/MainApplication.java), this method functions as an uncaught-exception handler that monitors for `OutOfMemoryError` conditions.

When an OOM is detected, the system immediately executes two critical mitigations:

- **Data Source Switching**: Changes the player data source from the memory-intensive OkHttp implementation to the lighter default option (`PlayerTweaksData.PLAYER_DATA_SOURCE_DEFAULT`)
- **Buffer Downgrade**: Reduces the video buffer size from `BUFFER_HIGH` or `BUFFER_HIGHEST` to `BUFFER_MEDIUM`, significantly decreasing RAM allocation for video caching

This preventive approach ensures that future playback operations consume less memory, reducing the likelihood of recurring OOM errors during the same application session.

## Playback-Engine Error Fixer: Reactive Recovery

The second layer operates within the ExoPlayer error-handling flow through `ErrorFixerController.applyEngineErrorAction()` at lines 48-57 in [`common/src/main/java/com/liskovsoft/smartyoutubetv2/common/app/models/playback/controllers/ErrorFixerController.java`](https://github.com/yuliskov/SmartTube/blob/main/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/app/models/playback/controllers/ErrorFixerController.java). This controller catches OOM exceptions that bubble up from the renderer during active playback.

When memory pressure surfaces mid-stream, the controller implements finer-grained recovery options:

1. **Force Lighter Data Source**: Compels an immediate switch to faster, less memory-intensive data sources
2. **Lower Buffer Levels**: Adjusts runtime buffer configurations to free allocated memory
3. **Disable Section Playlist**: Stops heavy loading operations that consume additional RAM

The method then determines whether to perform a **soft reload** (`reloadVideo()`) or **hard restart** (`mVideoLoaderController.restartEngine()`) based on the severity of the memory condition and the selected mitigation strategy.

## Configuration Classes Supporting OOM Recovery

SmartTube's recovery mechanisms rely on specific data models to persist and apply memory optimizations:

- **`PlayerTweaksData`**: Stores mutable player configuration including data source types and buffer preferences used by both recovery layers
- **`PlayerData`**: Manages runtime playback parameters such as `BUFFER_HIGH`, `BUFFER_MEDIUM`, and `BUFFER_LOW` constants that define memory allocation limits

These classes enable the application to maintain persistent preferences across recovery cycles, ensuring that once an OOM triggers a downgrade, the system remembers the lighter configuration for subsequent operations.

## Practical Code Examples

### Triggering OOM Recovery Manually

Developers can test the recovery mechanisms by forcing an OutOfMemoryError and routing it through SmartTube's error handlers:

```java
// Force an OutOfMemoryError to verify recovery behavior
try {
    // Allocate a huge byte array to provoke OOM
    byte[] huge = new byte[Integer.MAX_VALUE];
} catch (OutOfMemoryError e) {
    // Apply global crash fixes
    MainApplication app = (MainApplication) getApplicationContext();
    app.applyCrashFixes(e);
    
    // Apply playback-level fixes if player is active
    ErrorFixerController ctrl = ErrorFixerController.instance(app);
    ctrl.applyEngineErrorAction(
        PlayerEventListener.ERROR_TYPE_UNEXPECTED,
        PlayerEventListener.RENDERER_INDEX_UNKNOWN,
        e
    );
}

```

Executing this code triggers the automatic mitigation sequence, switching the data source from OkHttp to default and reducing buffer sizes from `BUFFER_HIGH` to `BUFFER_MEDIUM`.

### Proactive Memory Configuration

To prevent initial OOM occurrences on low-memory devices, configure the fallback settings before starting playback:

```java
// Configure lighter data source preemptively
PlayerTweaksData tweaks = PlayerTweaksData.instance(context);
tweaks.setPlayerDataSource(PlayerTweaksData.PLAYER_DATA_SOURCE_DEFAULT);
tweaks.persistNow();

```

This configuration eliminates the need for runtime recovery by selecting memory-efficient defaults from application startup.

## Summary

- **Two-layer defense**: SmartTube combines global exception handling in `MainApplication` with playback-specific recovery in `ErrorFixerController` to intercept OOM errors at different architectural levels according to the SmartTube source code.
- **Automatic resource downgrading**: The system switches from OkHttp to default data sources and reduces buffers from `BUFFER_HIGH`/`BUFFER_HIGHEST` to `BUFFER_MEDIUM` when memory pressure is detected.
- **Granular recovery options**: The playback controller chooses between engine restart and video reload based on error severity, minimizing user disruption.
- **Persistent configuration**: Changes made during OOM recovery are stored in `PlayerTweaksData`, ensuring subsequent playback operations use memory-efficient settings.

## Frequently Asked Questions

### What triggers OutOfMemoryError in SmartTube?

OutOfMemoryError exceptions typically occur when SmartTube loads high-resolution video streams using the OkHttp data source while maintaining large buffer sizes (`BUFFER_HIGH` or `BUFFER_HIGHEST`). Android TV devices with limited RAM cannot simultaneously handle the memory overhead of OkHttp connections, extensive video caching, and system operations, causing the virtual machine to exhaust available heap space during playback or buffering operations.

### How does SmartTube recover without crashing the entire app?

SmartTube implements a global uncaught-exception handler in `MainApplication.applyCrashFixes()` that intercepts OOM exceptions before they terminate the process. By catching the error at the application level, the code switches to lighter data sources and reduces buffer allocations, then allows execution to continue. If the error occurs during active playback, `ErrorFixerController.applyEngineErrorAction()` performs targeted recovery by restarting only the ExoPlayer engine rather than the entire application process.

### Can users configure settings to prevent OOM errors?

Yes, users can proactively configure memory-efficient settings through `PlayerTweaksData` by selecting `PLAYER_DATA_SOURCE_DEFAULT` instead of the OkHttp implementation and choosing smaller buffer sizes like `BUFFER_MEDIUM` or `BUFFER_LOW`. These configurations reduce the baseline memory footprint, preventing the conditions that typically trigger OutOfMemoryError exceptions on constrained Android TV hardware.

### What is the difference between restartEngine and reloadVideo?

`restartEngine()` performs a complete restart of the ExoPlayer instance through `mVideoLoaderController`, clearing all renderer states and reinitializing the playback pipeline, which is necessary when severe memory corruption occurs. `reloadVideo()` performs a softer recovery by reloading the current media item without destroying the player instance, preserving more playback state and providing faster recovery when the memory issue can be resolved through simple buffer adjustments alone.