Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug Video player holds unto a chunk of memory IOS

Discussion in 'Audio & Video' started by marcusdyrholm, Sep 29, 2023.

  1. marcusdyrholm

    marcusdyrholm

    Joined:
    Mar 18, 2021
    Posts:
    11
    Hi, I'm using Unity 2022.3.10. I am encountering a strange issue after updating from Unity 2021.3.5. I have a scene where I download a video in the form of a byte array and create a video file in the persistent data path. I then load the video into a video player and render it to a render texture. Previously, when the video ends and the prefab which holds the video player and render texture, gets destroyed the memory that the video player was holding unto gets released. However in this new Unity version it seems that a part of this memory chunk is held. Here are the memory profiler views:

    Before loading video:
    upload_2023-9-29_10-23-37.png

    After loading video:
    upload_2023-9-29_10-24-11.png

    After ending video:
    upload_2023-9-29_10-24-36.png

    Here are the memory captures. They are not from the same session (i.e. I closed the app and opened it again)

    A = before loading video, B = after loading video
    upload_2023-9-29_10-40-47.png

    A = after loading video, B = after ending video.
    upload_2023-9-29_10-41-23.png

    I have a script that forces the garbage collector to collect everytime the app has a low memory warning. I also call the GC.Collect method when the video is closed. Has anyone else encountered this problem? Is there a potential fix for it?
     
  2. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,159
    Take snapshots from the same session and compare the details. What render textures get created from A1->B1 and which stick around after unloading? Use version 1.1.0-pre.1 of the package and make use of the instance IDs listed in the compare views, as well as the improved search feature of that version which allows you to filter by ID when doing same session comparisons.

    That sounds like a terrible idea. GC.Collect triggers automatically when new managed memory is needed, and will not unload native memory, like the one for Leaked Dynamically Runtime Created Assets, like a new Material or RenderTexture that you lost the references to before unloading and Destroying it. To forcefully unload these Leaked Dynamically Runtime Created Assets you can call Resources.UnloadUnusedAssets, but that's even more costly in terms of time spend on it than GC.Collect.

    Calling GC.Collect manual is liable to further fragment the managed heap. Speaking of: your big jump in fragmentated managed heap from A1->B1 is likely due to that byte array. That means it's likely a large chunk of contiguous reserved memory that could be used for the next larger allocations without needing to trigger a GC.Collect for quite a while. Another large allocation could also take that up. But if you call GC.Collect manually, there's the current (i.e. at least up to 2023+, just saying this because implementation details are not something to bank on and always something that could change and should therefore be re-evaluated when updating major versions) implementation detail of the Boehm GC, used in both Mono and IL2CPP, that every 6th GC Cycle, every entriely empty page (usually 4KB in size and alignment) of managed memory gets returned to the OS. That means that this big chunk will be relinquished on a per page basis, quite possibly leaving one or more pages with low occupancy and now a sub-page amount of free contiguous address space. So they are invalid for any new Multi-Page allocation, like the next video you might want to download. This is what I mean what I say that manual calling of GC.Collect is liable to fragment your heap, so proceed with caution.

    One way to avoid that whole managed fragmentation mess is if you can instead use NativeArray<Byte> for this operation, or UnsafeUtility.Malloc, or Marshal.AllocHGlobal (caution, that last one is untracked by Unity's memory manager and therefore won't show up in the Memory Profiler, or rather, only as a larger untracked amount.)
    Bonus points if you can reuse it for subsequent videos/downloads, or just use a streaming buffer of some sort.

    That said, I think your first priority is taking same session snapshots and using them to figure out what RenderTextures are getting created from A1->B1, then not getting released from A2(B1)->B2, and finding out why, i.e. checking their references in B2 as well as their Details (look for their Status in the Selected Item Details panel and eventual HideFlags).
     
  3. The_Island

    The_Island

    Unity Technologies

    Joined:
    Jun 1, 2021
    Posts:
    502
    We changed the backend on iOS significantly in 2022, so it is always possible there might be an issue. Something to remember is that sometimes the player doesn't release the memory and keeps it in a pool for other uses. To test for a memory leak, you can repeatedly stop and play a video every second and check if the memory continues to expand. If it does, please report it as a bug, and we will fix it.