Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java.lang.OutOfMemoryError #7354

Closed
jhwsx opened this issue May 10, 2020 · 24 comments
Closed

java.lang.OutOfMemoryError #7354

jhwsx opened this issue May 10, 2020 · 24 comments
Assignees

Comments

@jhwsx
Copy link

jhwsx commented May 10, 2020

05-10 17:00:35.832 E/AndroidRuntime(10905): java.lang.OutOfMemoryError: Failed to allocate a 64 byte allocation with 4008 free bytes and 3KB until OOM
05-10 17:00:35.832 E/AndroidRuntime(10905): 	at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:95)
05-10 17:00:35.832 E/AndroidRuntime(10905): 	at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:146)
05-10 17:00:35.832 E/AndroidRuntime(10905): 	at java.lang.StringBuilder.append(StringBuilder.java:216)
05-10 17:00:35.832 E/AndroidRuntime(10905): 	at android.util.Log.e(Log.java:243)
05-10 17:00:35.832 E/AndroidRuntime(10905): 	at com.google.android.exoplayer2.util.Log.e(Log.java:140)
05-10 17:00:35.832 E/AndroidRuntime(10905): 	at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:397)
05-10 17:00:35.832 E/AndroidRuntime(10905): 	at android.os.Handler.dispatchMessage(Handler.java:107)
05-10 17:00:35.832 E/AndroidRuntime(10905): 	at android.os.Looper.loop(Looper.java:205)
05-10 17:00:35.832 E/AndroidRuntime(10905): 	at android.os.HandlerThread.run(HandlerThread.java:61)
@krocard
Copy link
Contributor

krocard commented May 11, 2020

Your app was using all its allowed memory and ExoPlayer was denied allocating a small 64B object. Without more context as to what was using all the memory in your app, I can not help you.

Please provide complete information as requested in the issue template. The issue template can be found here. If you're unable to share bug reports or test content publicly, please send them to dev.exoplayer@gmail.com using a subject in the format "Issue #1234", where "#1234" should be replaced with your issue number. Please also update this issue to indicate you’ve done this.

@krocard krocard self-assigned this May 11, 2020
@jhwsx
Copy link
Author

jhwsx commented May 12, 2020

I don't know what information I need to provide. What about some logs?
xiaolajiao05121024.txt
I have used AndroidStudio Profiler to point the issue. In fact, when I use ExoPlayer in my code, the memory size is high(about 150M), while only 64M when I use VideoView of android sdk.

And the log may not point to ExoPlayer sometimes, but ExoPlayer actually accupy too much memory, which leads to OOM fatally.

@krocard If you need more information, please feel free to tell me what to do. I really want to find the root cause. Thanks.

@krocard
Copy link
Contributor

krocard commented May 12, 2020

From your log, it seems the system is only allowing your app to allocate 128MB of memory.

05-12 10:24:40.703 I/aoc     ( 2693): Alloc concurrent mark sweep GC freed 11(336B) AllocSpace objects, 0(0B) LOS objects, 0% free, 127MB/128MB, paused 1.115ms total 40.982ms

Quickly skimming through the log I'm not sure why the memory is so limited. There are codec used (OMX.MTK.VIDEO.DECODER.AVC), but 128MB is very limited.

Which Xiaolajiao device are you using, and how many memory does it has?
Also, what is the bitrate of the file you are playing?

@ojw28
Copy link
Contributor

ojw28 commented May 13, 2020

If you're not already doing so, it may be a good idea to enable largeHeap to see if that helps. See here for an example.

@jhwsx
Copy link
Author

jhwsx commented May 14, 2020

Honglajiao Note4X Android 6.0, API 23。
Memory:3GB

@jhwsx
Copy link
Author

jhwsx commented May 14, 2020

xiaolajiao
file info:

$ ffmpeg -i seconds44.mp4 
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'seconds44.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    creation_time   : 2020-03-17T09:23:36.000000Z
    com.android.version: 9
  Duration: 00:00:44.25, start: 0.000000, bitrate: 42094 kb/s
    Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuvj420p(pc, bt470bg/bt470bg/smpte170m), 3840x2160, 41926 kb/s, SAR 1:1 DAR 16:9, 30.24 fps, 90k tbr, 90k tbn, 180k tbc (default)
    Metadata:
      rotate          : 90
      creation_time   : 2020-03-17T09:23:36.000000Z
      handler_name    : VideoHandle
    Side data:
      displaymatrix: rotation of -90.00 degrees
    Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 96 kb/s (default)
    Metadata:
      creation_time   : 2020-03-17T09:23:36.000000Z
      handler_name    : SoundHandle

The video is short but very large(about 249 MB), so I cannot upload it.

@jhwsx
Copy link
Author

jhwsx commented May 14, 2020

Here are some other logs:

2020-05-14 16:38:27.974 7866-8302/com.koki.callshow E/ExoPlayerImplInternal: Source error.
    com.google.android.exoplayer2.upstream.Loader$UnexpectedLoaderException: Unexpected OutOfMemoryError: Failed to allocate a 65552 byte allocation with 23688 free bytes and 23KB until OOM, max allowed footprint 268435456, growth limit 268435456
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:421)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)
     Caused by: java.lang.OutOfMemoryError: Failed to allocate a 65552 byte allocation with 23688 free bytes and 23KB until OOM, max allowed footprint 268435456, growth limit 268435456
        at com.google.android.exoplayer2.upstream.DefaultAllocator.allocate(DefaultAllocator.java:102)
        at com.google.android.exoplayer2.source.SampleDataQueue.preAppend(SampleDataQueue.java:392)
        at com.google.android.exoplayer2.source.SampleDataQueue.sampleData(SampleDataQueue.java:181)
        at com.google.android.exoplayer2.source.SampleQueue.sampleData(SampleQueue.java:471)
        at com.google.android.exoplayer2.extractor.mp4.Mp4Extractor.readSample(Mp4Extractor.java:552)
        at com.google.android.exoplayer2.extractor.mp4.Mp4Extractor.read(Mp4Extractor.java:192)
        at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:982)
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:391)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
        at java.lang.Thread.run(Thread.java:764) 

@jhwsx
Copy link
Author

jhwsx commented May 14, 2020

Here is my demo: ExoPlayer2Demo.zip
I can see the OOM error in this simple demo:

2020-05-14 19:15:16.129 27991-28045/com.example.exoplayer2demo E/LoadTask: OutOfMemory error loading stream
      java.lang.OutOfMemoryError: Failed to allocate a 65552 byte allocation with 22984 free bytes and 22KB until OOM, max allowed footprint 268435456, growth limit 268435456
        at com.google.android.exoplayer2.upstream.DefaultAllocator.allocate(DefaultAllocator.java:102)
        at com.google.android.exoplayer2.source.SampleDataQueue.preAppend(SampleDataQueue.java:392)
        at com.google.android.exoplayer2.source.SampleDataQueue.sampleData(SampleDataQueue.java:181)
        at com.google.android.exoplayer2.source.SampleQueue.sampleData(SampleQueue.java:471)
        at com.google.android.exoplayer2.extractor.mp4.Mp4Extractor.readSample(Mp4Extractor.java:552)
        at com.google.android.exoplayer2.extractor.mp4.Mp4Extractor.read(Mp4Extractor.java:192)
        at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:982)
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:391)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)
2020-05-14 19:16:02.960 27991-28032/com.example.exoplayer2demo E/ExoPlayerImplInternal: Source error
      com.google.android.exoplayer2.upstream.Loader$UnexpectedLoaderException: Unexpected OutOfMemoryError: Failed to allocate a 65552 byte allocation with 22984 free bytes and 22KB until OOM, max allowed footprint 268435456, growth limit 268435456
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:421)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)
     Caused by: java.lang.OutOfMemoryError: Failed to allocate a 65552 byte allocation with 22984 free bytes and 22KB until OOM, max allowed footprint 268435456, growth limit 268435456
        at com.google.android.exoplayer2.upstream.DefaultAllocator.allocate(DefaultAllocator.java:102)
        at com.google.android.exoplayer2.source.SampleDataQueue.preAppend(SampleDataQueue.java:392)
        at com.google.android.exoplayer2.source.SampleDataQueue.sampleData(SampleDataQueue.java:181)
        at com.google.android.exoplayer2.source.SampleQueue.sampleData(SampleQueue.java:471)
        at com.google.android.exoplayer2.extractor.mp4.Mp4Extractor.readSample(Mp4Extractor.java:552)
        at com.google.android.exoplayer2.extractor.mp4.Mp4Extractor.read(Mp4Extractor.java:192)
        at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:982)
        at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:391)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
        at java.lang.Thread.run(Thread.java:764) 

@krocard
Copy link
Contributor

krocard commented May 14, 2020

I think this OOM is due to several factor:

  1. the media file you are playing is 42 Mbps which is very high,
  2. Probably your app does not request a big enough heap, consider enabling largeHeap to see if that helps. See java.lang.OutOfMemoryError #7354 (comment)
  3. Maybe DefaultLoadControl.setPrioritizeTimeOverSizeThresholds is set to true, which would not set a limit on the buffer size. Please check if that is the case.
  4. Finally the mp4 file itself might be structured in such a way that just requires ExoPlayer to load lots of data before playback can start. It would be helpful if you could send us the media file you trying to play. Either upload it here, or past a link to a google drive file, or send it (or a google drive link to it) to dev.exoplayer@gmail.com using a subject in the format "Issue Support multiple TXXX ID3 tags #1234", where "Support multiple TXXX ID3 tags #1234" should be replaced with your issue number. Please also update this issue to indicate you’ve done this.

@jhwsx
Copy link
Author

jhwsx commented May 14, 2020

When I go to office, I'll send it to your email asap. I think I have to enable largeHeap now, which, though, is not a very good solution.

@jhwsx
Copy link
Author

jhwsx commented May 15, 2020

The media file has been sent to dev.exoplayer@gmail.com.

@jhwsx
Copy link
Author

jhwsx commented May 18, 2020

@krocard How is it going? May I ask that whether you have any workaround about this issue?

@krocard
Copy link
Contributor

krocard commented May 19, 2020

@jhwsx Your issue is high on my priority list, and I'm planning to build your test app to take a loop at why the memory usage is so high, but I have other tasks too.
I will come back to you when I have some results.

@krocard
Copy link
Contributor

krocard commented May 20, 2020

The media file has been sent to dev.exoplayer@gmail.com.

@jhwsx Thanks, we received the link. I unfortunately do not have have the permission to access the file. Could you give me read access? You should have received an email with my permission request.

@jhwsx
Copy link
Author

jhwsx commented May 21, 2020

Sorry,but I‘m not familiar the use of Gmail. I have enabled sharing settings by clicking a button. Could you please check whether the read access has been given.
Thank you very much.

@krocard
Copy link
Contributor

krocard commented May 21, 2020

Thanks @jhwsx, I was able to download your media. Will test it now.

@krocard
Copy link
Contributor

krocard commented May 21, 2020

The issue seems to come from the SampleDataQueue. It allocates an 132MB link list of of more than 2000 element, each containing a Byte[] array of around 64kiB.

This also forces many garbage collection, around ~31 per second. (I also wonder if a 2k depth is bad for GC perf?)

@krocard
Copy link
Contributor

krocard commented May 21, 2020

Duration: 00:00:44.25, start: 0.000000, bitrate: 42094 kb/s

Given that the file bitrate is 42Mb/s, and that the default buffer size is 5s 50s, 210MB 260MB (1) are expected. I observe 123MB though.

What is also surprising is that the DEFAULT_VIDEO_BUFFER_SIZE is of 500 elements of 64k (32MB). But I'm measuring 2k element in the link list.

(1) the bitrate is in bits, not bytes and 50000 is 50s, not 5s, as corrected by @ojw28,

@ojw28
Copy link
Contributor

ojw28 commented May 21, 2020

Given that the file bitrate is 42MB per second, and that the default buffer size is 5s, 210MB are expected.

That's 42Mbit/s right? So you'd only expect 210/8 = 26MBytes for 5 seconds.

@krocard
Copy link
Contributor

krocard commented May 21, 2020

@jhwsx, by setting prioritizeTimeOverSizeThreasholds to false, the sample queue is limited to around the expected 32MB.

@krocard
Copy link
Contributor

krocard commented May 21, 2020

That's 42Mbit/s right? So you'd only expect 210/8 = 26MBytes for 5 seconds.

Correct. I definitely do not understand why so much memory is used then.

@tonihei could you take a look?

@jhwsx, by setting prioritizeTimeOverSizeThreasholds to false, the sample queue is limited to around the expected 32MB.

In your demo app, this could be done as such:

 SimpleExoPlayer player = new SimpleExoPlayer.Builder(MainActivity.this,
        new DefaultRenderersFactory(MainActivity.this))
    .setLoadControl(new DefaultLoadControl.Builder()
        .setPrioritizeTimeOverSizeThresholds(false)
        .createDefaultLoadControl())
    .build();

@ojw28
Copy link
Contributor

ojw28 commented May 21, 2020

The default buffer size is 50 seconds, not 5. So that probably explains the difference.

@krocard
Copy link
Contributor

krocard commented May 21, 2020

The default buffer size is 50 seconds, not 5. So that probably explains the difference.

Definitely explains it then, thanks for double checking my (wrong) math.

@jhwsx
Copy link
Author

jhwsx commented May 22, 2020

Well done!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants