vlc-android-sdk icon indicating copy to clipboard operation
vlc-android-sdk copied to clipboard

Memory Leak in MediaPlayer.Event and VLCObject.EventRunnable

Open SaundersB opened this issue 7 years ago • 0 comments

When implementing my own event listener for a media player, I found that the heap displays a massive amount of MediaPlayer.Events and VLCObject.EventRunnables. In some cases I see 3,000-8,000 instances of these events or event runnables.

There are two places I see this happening:

  • At the inner class where the EventRunnable is being created and posted with the event handler.
  • And where the event is dispatched via the weak native event. I don't know how this is being handled in the native library, but it seems something is amiss.

I'm using both vlc-android 2.0.6 and 2.1.2.

/* JNI */
    @SuppressWarnings("unused") /* Used from JNI */
    private long mInstance = 0;
    private synchronized void dispatchEventFromNative(int eventType, long arg1, float arg2) {
        if (isReleased())
            return;
        final T event = onEventNative(eventType, arg1, arg2);

        class EventRunnable implements Runnable {
            private final VLCEvent.Listener<T> listener;
            private final T event;

            private EventRunnable(VLCEvent.Listener<T> listener, T event) {
                this.listener = listener;
                this.event = event;
            }
            @Override
            public void run() {
                listener.onEvent(event);
            }
        }

        if (event != null && mEventListener != null && mHandler != null) {
            mHandler.post( new EventRunnable(mEventListener, event));
        }
    }
@SuppressWarnings("unchecked,unused") /* Used from JNI */
    private static void dispatchEventFromWeakNative(Object weak, int eventType, long arg1, float arg2) {
        VLCObject obj = ((WeakReference<VLCObject>)weak).get();
        if (obj != null) {
            obj.dispatchEventFromNative(eventType, arg1, arg2);
            obj.release();
        }
    }
  • My PlayerListener:
public class PlayerListener implements MediaPlayer.EventListener {
    private final static String TAG = PlayerListener.class.getSimpleName();

    private static WeakReference<Player> mOwner;

    PlayerListener(Player owner) {
        mOwner = new WeakReference<>(owner);
    }

    @Override
    public void onEvent(MediaPlayer.Event event) {
        Player player = mOwner.get();

        if(player != null) {
            switch (event.type) {
                case MediaPlayer.Event.EndReached:
                    Log.i(TAG, "EndReached------------------");
                    break;
                case MediaPlayer.Event.Playing:
                    Log.i(TAG, "Playing------------------");
                    break;
                case MediaPlayer.Event.Paused:
                    Log.i(TAG, "Paused------------------");
                    break;
                case MediaPlayer.Event.Stopped:
                    Log.i(TAG, "Stopped------------------");
                    break;
                case MediaPlayer.Event.PositionChanged:
                    //Log.i(TAG, "Position Changed------------------: " + player.getMediaPosition());
                    break;
                case MediaPlayer.Event.MediaChanged:
                    Log.i(TAG, "MediaChanged------------------");
                    break;
                case MediaPlayer.Event.Vout:
                    Log.i(TAG, "Vout------------------");
                    break;
                case MediaPlayer.Event.ESAdded:
                    Log.i(TAG, "ESAdded------------------");
                    break;
                case MediaPlayer.Event.ESDeleted:
                    Log.i(TAG, "ESAdded------------------");
                    break;
                case MediaPlayer.Event.Opening:
                    Log.i(TAG, "Opening------------------");
                    break;
                case MediaPlayer.Event.Buffering:
                    Log.i(TAG, "Buffering------------------");
                    break;
                case MediaPlayer.Event.TimeChanged:
                    // Log.i(TAG, "TimeChanged------------------: " + player.actualPlaybackLength);
                    break;
                case MediaPlayer.Event.SeekableChanged:
                    Log.i(TAG, "SeekableChanged------------------");
                    break;
                case MediaPlayer.Event.EncounteredError:
                    Log.e(TAG, "EncounteredError------------------");
                    break;
                case MediaPlayer.Event.PausableChanged:
                    Log.i(TAG, "PausableChanged------------------");
                    break;
                default:
                    break;
            }
        } else {
            Log.i(TAG, "Player class is null in Player Listener.");
        }
    }
}

SaundersB avatar Mar 30 '17 18:03 SaundersB