Search code examples
swiftavasset

Why is my swift app "leaking" memory in AVAsset


While retrieving metadata from media files, I've run into a memory issue I cannot figure out.

I want to retrieve metadata for media files either stored in the local app storage or in the iTunes area. For this I use AVAsset. While looping through these files I can see the memory consumption rising constantly. And not just a little. It is significant and end up stalling the app when I enumerate my iTunes library on the phone.

The problem seems to be accessing the metadata property on the AVAsset class. I've narrowed in down to one line of code: 'let meta = ass.metadata'. Having that line of code (without any references) makes the app consume memory. I've included an example of my code structure.

func processFiles(_ files:Array)
{
  var lastalbum : String = ""
  var i         : Int    = 0
  for file in files
  {
    i += 1
    view.setProgressPosition(CGFloat(i)/CGFloat(files.count))
    lastalbum = updateFile(file.url,lastalbum,
    { (album,title,artist,composer) in
      view.setProgressNote(album,title,artist+" / "+composer)
    })
  }
}

func updateFile(_ url:URL,_ lastalbum:String,iPod:Bool=false,
                _ progress:(String,String,String,String) -> Void) -> String
{
  let ass = AVAsset(url:url)
  let meta = ass.metadata

  for item in meta
  {
    // Examine metadata
  }
  // Use metadata
  // Callback with status
}

It seems that memory allocated in the updateFile method, is kept, even when the function is ended. However, once the processFile function completes and the app returns to a normal state, all memory is released again.

So in conclusion, this is not a real leak, but still a significant problem. Any good ideas as to what goes wrong? Is there any way I can force the memory management to run a cleanup?


Solution

  • As suggested in the comment on the post, the solution for this is to wrap the specific code in a 'autoreleasepool' block. I've tested this both with a small set of local media files and also with my rather large iTunes media library (70GB). After implementing the 'autoreleasepool' the memory buildup is eliminated.

    func updateFile(_ url:URL,_ lastalbum:String,iPod:Bool=false,
                    _ progress:(String,String,String,String) -> Void) -> String
    {
      autoreleasepool
      {
        let ass = AVAsset(url:url)
        let meta = ass.metadata
    
        for item in meta
        {
          // Examine metadata
        }
        // Use metadata
        // Callback with status
      }
    }