Skip to content

Repeatedly calling Player.replaceMediaItem() leaks MediaItem objects #2993

@litrik

Description

@litrik

Version

Media3 main branch

More version details

Commit da54b91

Devices that reproduce the issue

Any device

Devices that do not reproduce the issue

No response

Reproducible in the demo app?

Yes

Reproduction steps

Add the following inner class to DemoPlaybackService:

    inner class UpdateMetadataWhilePlayingListener : Player.Listener {

        private var metadataJob: Job? = null

        override fun onIsPlayingChanged(isPlaying: Boolean) {
            if (isPlaying) {
                metadataJob = GlobalScope.launch {
                    var i = 0
                    while (true) {
                        delay(1000)
                        i++
                        withContext(Dispatchers.Main) {
                            mediaLibrarySession.player.currentMediaItem?.let { mediaItem ->
                                mediaLibrarySession.player.replaceMediaItem(
                                    mediaLibrarySession.player.currentMediaItemIndex,
                                    mediaItem
                                        .buildUpon()
                                        .setMediaMetadata(
                                            mediaItem.mediaMetadata.buildUpon()
                                                .setTitle("Title " + i).build()
                                        )
                                        .build(),
                                )
                            }
                        }
                    }
                }
            } else {
                metadataJob?.cancel()
            }
        }
    }

Add the follwoing line to DemoPlaybackService.buildPlayer()

exoPlayer.addListener(UpdateMetadataWhilePlayingListener())

This code is the loop of #2468 (comment) that calls player.replaceMediaItem() every second to update the session metadata.

Start the demo-session app and start playing any song.

Expected result

No memory leak

Actual result

When you let the demo app run for e.g. 150 seconds and you open the profiler you'll see that there are roughly 150 androidx.media3.common.MediaItem objects in memory. The longer the audio plays, more objects are kept in memory. This is a memory leak.

Image

It looks like these MediaItem objects are accumulated through the TimelineWithUpdatedMediaItem class.

Image

I'm not very familiar with the internals of the Media3 framework but there are some pointers to Analytics code that is at the root of all these MediaItem objects.

Image

I'm suspicious about DefaultAnalyticsCollector. It contains a SparseArray<EventTime> eventTimes where put() gets called, but there is never any remove() (AFAIK).

PS: This is a small memory leak but we do observe it in production on low-end devices where users listen to a live radio stream for multiple hours.

Media

Tested with the Media3 Session demo app, folder "Album folder", folder "Jazz & Blues"

Bug Report

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions