2014-09-09 1 views
3

J'essaie d'apprendre Swift et j'ai donc écrit une petite application de test à cette fin. Il donne simplement la taille totale des éléments dans un répertoire, récursif dans les sous-répertoires pour accumuler la taille totale de leur contenu. L'application fonctionne, mais l'utilisation de la mémoire ne cesse de croître et de croître pendant son exécution. Je m'attendais à ce que l'utilisation de la mémoire augmente à mesure que la récursivité devienne plus profonde et diminue quand un appel récursif revient. Au lieu de cela, l'utilisation de la mémoire grimpe constamment. Instruments n'identifie aucune fuite. J'ai essayé quelques trucs que j'ai trouvé dans divers résultats de Google, y compris:Impossible de trouver une fuite de mémoire dans l'application Swift

en réutilisant la valeur par défaut NSFileManager pas réutilisant la valeur par défaut NSFileManager mais créer un nouveau pour chaque appel récursif évitant chaîne interpolation

Rien ne semble faire de différence. J'avais pensé que Swift nettoierait les objets lorsque leur compte de référence atteindrait zéro.

C'est le code dans son intégralité dans son état actuel:

import Foundation 

func sizeOfContents(path: String) -> UInt64 
{ 
    let subManager = NSFileManager() 
    var totalSize: UInt64 = 0; 
    var isDir: ObjCBool = false 
    if subManager.fileExistsAtPath(path, isDirectory: &isDir) 
    { 
     if !isDir.boolValue 
     { 
      var error: NSError? = nil 
      let attributes: NSDictionary? = subManager.attributesOfItemAtPath(path, error: &error) 
      let size: UInt64? = attributes?.fileSize() 
      totalSize += size! 
     } 
     else 
     { 
      var error: NSError? = nil 
      if let subContents = subManager.contentsOfDirectoryAtPath(path, error: &error) 
      { 
       for subItem in subContents 
       { 
        var subName = subItem as String 
        subName = path + "/" + subName 
        totalSize += sizeOfContents(subName) 
       } 


      } 
     } 
    } 

    return totalSize 
} 

let manager = NSFileManager.defaultManager() 
var rootPath = "/Applications/" 
if let contents = manager.contentsOfDirectoryAtPath(rootPath, error: nil) 
{ 
    for item in contents 
    { 
     let itemName = item as String 
     var isDir: ObjCBool = false 
     print("item: " + (rootPath + itemName)) 
     if manager.fileExistsAtPath(rootPath + itemName, isDirectory: &isDir) 
     { 
      if !isDir.boolValue 
      { 
       var error: NSError? = nil 
       let attributes: NSDictionary? = manager.attributesOfItemAtPath(rootPath + itemName, error: &error) 
       let size: UInt64? = attributes?.fileSize() 
       println("\t\(size!)") 
      } 
      else 
      { 
       if(itemName != "Volumes") 
       { 
        let size = sizeOfContents(rootPath + itemName) 
        println("\t\(size)") 
       } 
      } 
     } 
    } 
} 

Répondre

2

Vous devez ajouter un autoreleasepool dans la boucle, peut-être autour de l'appel récursif. Comme il s'agit d'une boucle serrée, la boucle d'attente n'obtient pas de modification pour libérer les allocations de mémoire temporaire.

exemple:

... 
autoreleasepool { 
    totalSize += sizeOfContents(subName) 
} 
... 
+0

Ce fut tout. Maintenant, je dois aller lire sur autoreleasepool. L'application ne dépasse plus jamais 6,4 Mo lorsque je la lance à partir de "/", alors qu'auparavant elle dépassait les 60 Go, et qu'elle fonctionne beaucoup plus vite. Il ne le mentionne jamais dans le livre Swift Programming Language, mais j'ai trouvé quelque chose à ce sujet dans une session de la WWDC (Improving Your App With Instruments). Merci beaucoup! – aranha

Questions connexes