Gestion De La Mémoire Swift

cette question a été nettoyée et l'information importante déplacée à la réponse ci-dessous.


j'ai quelques questions sur la gestion de la mémoire.

je construis une application de retouche photo. Il est donc important de maintenir un faible niveau d'utilisation de la mémoire. En outre, Je ne vais pas poster de code parce que je n'ai pas une grande fuite de mémoire en faisant une chose spécifique. Je perds juste quelques KB / MB avec tout ce qui se passe. Et d'aller sur des dizaines de milliers de lignes de code pour trouver kilo-octets n'est pas drôle ;)

mon application utilise des données de base, beaucoup de cifilter choses, l'emplacement et les bases.

ma première vue est juste une vue de table qui me coûte environ 5mb de mémoire. Ensuite vous prenez quelques photos, appliquez quelques filtres, cela est enregistré aux données de base et ensuite vous retournez à cette première vue.

est-il possible de vraiment se débarrasser de tout en mémoire sauf pour les données nécessaires pour conduire cette première vue. (que très sauvegarder et génial 5mo)

ou y aura-t-il toujours quelque chose de laissé derrière, même si vous mettez tout à zéro?


Question Bonus: y a-t-il une différence de taille de fichier / charge cpu entre UIImageJPEGRepresentation et UIImagePNGRepresentation ? Je sais que vous pouvez définir une qualité de compression avec la méthode JPEG (plus dure sur le cpu/gpu?).

j'essaie juste de réduire pression de mémoire par tous les moyens possibles.


mise à jour:

on m'a fait remarquer que la question pourrait être trop vague.

les problèmes que j'ai rencontrés à un moment ou à un autre étaient les suivants:

  • À certains points d'utilisation maximale de la mémoire est trop élevé
  • naviguer vers un second viewcontroller et retour provoque une fuite
  • éditer une image provoque une fuite de mémoire.
  • L'application d'un filtre à plus de 4-5 images provoque un crash à cause de la mémoire faible, il n'y avait plus de fuites de mémoire à ce point. (vérifié dans les instruments)

P. S tout cela a été testé sur un iPhone 4s, pas sur le simulateur.

il y avait un mème ici pour alléger un peu l'Humeur sur ce site.

22
demandé sur R Menke 2015-01-15 09:41:45

2 réponses

cette question a été ouverte assez longtemps et je me sens maintenant assez confiant pour y répondre.


différents niveaux de MM:

Mémoire Matérielle

dans Swift avec ARC nous n'avons aucun moyen de nettoyer la ram matérielle réelle. Nous ne pouvons que permettre à L'OS de le faire pour nous. Une partie utilise le droit code ( optionals et weak ) l'autre partie crée du temps pour que L'OS fasse son travail.

Imaginez que nous ayons une fonction qui fonctionne sur tous les threads indéfiniment. Il fait une chose, charger une image, convertir en noir / blanc et enregistrer. Toutes les images max à un couple de mb's et la fonction ne crée pas de fuites de mémoire logicielle. Parce que les images n'ont pas une taille définie et peuvent avoir une compression différente, elles n'ont pas la même empreinte. Cette fonction bloquera toujours votre application.

cette fuite de mémoire" matérielle " est causée par la fonction qui prend toujours le prochain emplacement de mémoire disponible.

L'OS n'intervient pas pour" effectivement nettoyer la mémoire " car il n'y a pas de temps mort. Mettre un délai entre chaque passe complètement corrige ce.


langues spécifiques MM

Casting

Certaines opérations n'ont pas un impact sur la mémoire, d'autres le font:

let myInt : Int = 1
Float(myInt) // this creates a new instance

Essayer de casting plutôt:

(myInt as Float) // this will not create a new instance.

types de référence vs types de valeur / Classes vs structures

tous deux ont leurs avantages et leurs dangers.

structures sont à forte intensité de mémoire parce qu'ils sont des types de valeur . Cela signifie qu'ils copient leurs valeurs lorsqu'elles sont affectées à une autre instance, effectivement utilisation de la mémoire de doublement . Il n'y a aucun correctif / travail autour pour cela. C'est ce qui fait des structures des structures des structures.

Classes n'ont pas ce comportement parce qu'ils sont Types de Référence . Ils ne copient pas une fois assignés. Au lieu de cela, ils créent une autre référence au même objet . ARC ou Automatique de Comptage de Référence est ce qui garde la trace de ces références. Chaque Objet a un compteur de référence. Chaque fois que vous l'assignez, il monte d'un. Chaque fois que vous définissez une référence à zéro, la fonction d'enclos se termine, ou l'objet d'enclos désintègre, le compteur descend.

lorsque le compteur atteint 0, l'objet est désinitialisé.

Il y a un moyen d'empêcher une instance de se désinitialiser, et donc de créer une fuite. C'est ce qu'on appelle un cycle de référence fort .

bonne explication de faible

class MyClass {

    var otherClass : MyOtherClass?

    deinit {
        print("deinit") // never gets called
    }
}

class MyOtherClass {

    var myclass : MyClass?

    deinit {
        print("deinit") // never gets called
    }
}

var classA : MyClass? = MyClass()

// sorry about the force unwrapping, don't do it like this
classA!.otherClass = MyOtherClass()
classA!.otherClass!.myclass = classA // this looks silly but in some form this happens a lot

classA = nil
// neither the MyClass nor the MyOtherClass deinitialised and we no longer have a reference we can acces. Immortalitiy reached they have.

placer une référence à weak

class MyOtherClass {

    weak var myclass : MyClass?

    deinit {
        print("deinit") // gets called
    }
}

inout

Les fonctions

capturent les valeurs qui leur sont transmises. Mais il est également possible de marquer ces valeurs inout. Cela vous permet de changer une structure passée à une fonction sans copier la structure. Cela peut sauver de la mémoire, en fonction de ce que vous passez et ce que vous faites dans la fonction.

c'est aussi une bonne façon d'avoir des valeurs de retour multiples sans utiliser de tuples.

var myInt : Int = 0

// return with inout
func inoutTest(inout number: Int) {

    number += 5

}

inoutTest(&myInt)
print(myInt) // prints 5

// basic function with return creates a new instance which takes up it's own memory space
func addTest(number:Int) -> Int {

    return number + 5

}

Programmation Fonctionnelle

L'État

est la valeur sur Time

programmation Fonctionnelle est la contre-partie de la programmation Orientée Objet. Programmation fonctionnelle utilise état Immuable.

plus sur ce ici

Object Oriented programming uses object that have changing/muting states. Au lieu de créer une nouvelle valeur, les anciennes valeurs sont mises à jour.

la programmation fonctionnelle peut utiliser plus de mémoire.

exemple sur FP


optionnels

Les options

vous permettent de mettre la chose à zéro. Cela diminuera le nombre de référence des Classes ou Désinitialisera les structures. Mettre les choses à zéro est la façon la plus facile de nettoyer la mémoire. Cela va de pair avec l'ARC. Une fois que vous avez défini toutes les références d'une classe à zéro, il désinitera et libérera la mémoire.

si vous ne créez pas une instance en option, les données resteront en mémoire jusqu'à la fin de la fonction d'enclos ou jusqu'à la fin de la classe d'enclos. Vous ne savez peut-être pas quand cela arrivera. Les options vous donnent le contrôle sur ce qui reste en vie pour combien de temps.


API MM

de nombreuses "fuites de mémoire" sont causées par Frameworks qui ont une fonction de" nettoyage " que vous pourrait ne pas avoir appelé. Un bon exemple est UIGraphicsEndImageContext() le contexte restera dans la mémoire jusqu'à ce que cette fonction soit appelée. Il ne nettoie pas lorsque la fonction qui a créé le contexte se termine, ou lorsque l'image impliqués est définie à zéro.

un autre bon exemple est le rejet des contrôleurs de vue. Il serait peut-être logique de faire la transition vers une CV et de la faire revenir en arrière, mais la transition crée en fait une CV. Un retour en arrière ne détruit pas un CV. Appelez dismissViewControllerAnimated() pour l'enlever de la mémoire.

lire les références de classe et double vérification il n'y a pas de fonctions" nettoyer".


si vous avez besoin d'Instruments pour trouver une fuite, consultez l'autre réponse à cette question.

27
répondu R Menke 2017-04-12 07:31:24

enter image description here

cliquez sur le nom de votre application dans le coin supérieur droit de Xcode.

enter image description here

cliquez sur "modifier" dans le menu qui apparaît.

enter image description here

s'assurer que " RUN " est sélectionné sur le côté gauche, puis cliquez sur l'onglet diagnostics près du haut de la fenêtre.

sous la ' mémoire gestion de l'en-tête "cochez la case" activer le Gardien Malloc'

vous pouvez également essayer de vérifier 'objets distribués' et 'pile malloc' sous l'en-tête 'logging '

pour en savoir plus sur Guard malloc, guard edges et scribble, allez à ici .





espérons que cette aide!

6
répondu DeveloperACE 2017-05-23 12:18:04