[Résolu] Débutant avec Instrument

busterTheobusterTheo Membre
décembre 2016 modifié dans Apple Developer Programs #1

Bonjour,


je me penche actuellement sérieusement sur les problèmes de mémoire que j'aurai lorsque je publierai pour de vrai sur l'appStore, et j'ai trouvé un lien qui me va à  ravir concernant l'utilisation d'Instruments, et donc, la détection, dans le code, des sources de problème. J'ai enfin compris comment enquêter. Je respire.


 


à‰videmment, mon code est truffé de problèmes qui génèrent des "memory issues". Et honnêtement, je suis très heureux d'entrer dans ce fabuleux monde mystérieux.


 


Déjà , j'ai résolu un premier problème, et là  vous me direz si j'ai bien fait. Je pense que oui, car il s'agit des fameux poneys d'Aligator. Enfin, je pense...


 


--> J'avais dans mon fichier "AppDelegate.swift", ce code qui a été révélé par Instruments :



import UIKit
import CoreData

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
let containerViewController = ContainerViewController()
window!.rootViewController = containerViewController
window!.makeKeyAndVisible()
return true
}
...

que j'ai remplacé par :



import UIKit
import CoreData

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
if let window = window {
let containerViewController = ContainerViewController()
window.rootViewController = containerViewController
window.makeKeyAndVisible()
}
return true
}
...

grâce à  ce lien (tout en bas du post).


 


Je sais, que j'aurai du le corriger tout seul, sans l'aide de ce post, et selon les cours des barmen, et notamment d'Aligator. Mais maintenant que je peux jouer avec Instruments, je vais pouvoir sauver des milliers de poneys. Enfin, je l'espère. Il est vrai que je ne suis pas rendu, et que j'aurai du connaà®tre tout cela avant de commencer à  coder. Mais la vie n'est pas simple. :D


 


 


 


 


 


 


--> D'autre part, m'attaquant à  une autre source de "memory issue", j'arrive là -dessus, et là , je n'ai rien trouvé qui pourrait m'aider. C'est pourquoi, je reviens au bar.


 


Il s'agit d'une barre de navigation en haut du projet, que je configure au lancement.


Voici le code :



// NavBar
func configureNavbar(etapeViewController: UIViewController) {

etapeViewController.navigationItem.setHidesBackButton(true, animated: false)

let fixedSpace:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil)
fixedSpace.width = 36.0

let addPatientsButton: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "addButton.png"), style: .Plain, target: self, action: "nouveauPatient")
addPatientsButton.tintColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)

let patientsButton: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "patientsButton.png"), style: .Plain, target: self, action: "toggleNavPatients")
patientsButton.tintColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)

let prefsButton: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "gearButton.png"), style: .Plain, target: self, action: "prefsPatientsContainer:")
prefsButton.tintColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)

if listeDesVariables.edition == true {
etapeViewController.navigationItem.leftBarButtonItems = [fixedSpace, addPatientsButton, patientsButton, prefsButton]
} else {
etapeViewController.navigationItem.leftBarButtonItems = [fixedSpace, patientsButton, prefsButton]
}
}

Voici les lignes qui posent problème (environ 380KB):



etapeViewController.navigationItem.leftBarButtonItems = [fixedSpace, addPatientsButton, patientsButton, prefsButton]

et :



etapeViewController.navigationItem.leftBarButtonItems = [fixedSpace, patientsButton, prefsButton]

Voilà , si quelqu'un a une suggestion, je suis preneur.


 


Merci d'avance.


Réponses

  • CéroceCéroce Membre, Modérateur
    En quoi ça pose problème? Certes la taille des images parait un peu excessive, mais sinon, Instruments signale quoi ?
  • busterTheobusterTheo Membre
    mars 2016 modifié #3

    Merci de t'intéresser à  mon histoire...


     


    Ben, d'après le lien sur le tuto, je dois m'intéresser aux trucs en noir à  droite, en fait le tuto dit bold et moi je check les trucs noirs. Surement que je déconne...


     


    Sans quoi, ça me souligne en bleu dans le code et ça me dit environ 380KB.


     


    ​En fait, depuis tout-à -l'heure, je n'arrête pas de checker tous ces trucs, et je vois des consos mémoire de l'ordre de plusieurs MB, donc encore plus fort, et je ne sais pas si ça craint.


    Par ex. :



    func scaledImageWithImage(image: UIImage, size: CGSize) -> UIImage {
    let scale: CGFloat = max(size.width/image.size.width, size.height/image.size.height)
    let width: CGFloat = image.size.width * scale
    let height: CGFloat = image.size.height * scale
    let imageRect: CGRect = CGRectMake((size.width-width)/2.0, (size.height-height)/2.0, width, height)

    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    image.drawInRect(imageRect)
    let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage
    }

    J'ai entre 11 et 12 MB sur ces trois lignes :



    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    image.drawInRect(imageRect)
    let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()

    J'ai encore du mal à  interpréter.


     


    En tout cas, ça m'éclate vraiment de voir instruments sélectionner mes lignes de code. C'est la première fois que j'y parviens, grâce au lien du tuto. Maintenant, peut-être que je suis tellement certain d'avoir fait plein de conneries qui consomment de la mémoire, que dès qu'Instrument me souligne des lignes de code et me met des MB, je flippe bêtement...


     


    Comme aussi par. :



    func confPhoto() {
    let documentsDir = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask, true)[0]
    let fetchEntity: FetchEntity = FetchEntity()
    let fetchResults: NSArray = fetchEntity.getFetchResults("Patients", predicateField: listeDesVariables.nomString)
    let singlePatient: Patients = fetchResults.lastObject as! Patients
    let frontalPhoto = singlePatient.photoFrontal
    let pathFull:String = documentsDir + "/" + frontalPhoto
    if let zeImage: UIImage = UIImage(contentsOfFile: pathFull as String) {
    imageViewEtapes.image = zeImage
    imageViewEtapes.image = scaledImageWithImage(imageViewEtapes.image!, size: TaillePhotos)
    }

    if e1L6ZoomingString != "" {
    configOrientationPhoto(1, lz: CGFloat((e1L6ZoomingString as NSString).doubleValue), lx: CGFloat(Int(e1L6ZoomXString)!), ly: CGFloat(Int(e1L6ZoomYString)!))
    }
    }

    Là , il me met 18MB sur cette ligne :



    imageViewEtapes.image = scaledImageWithImage(imageViewEtapes.image!, size: TaillePhotos)

    En sachant que :



    let TaillePhotos: CGSize = CGSize(width: 560, height: 420)

    C'est lié aux 11 et 12 MB de la fonction scaledImageWithImage citée au-dessus...


     


     


    Merci


  • CéroceCéroce Membre, Modérateur
    Dans l'exemple de l'image, c'est normal: tu prends une image, et tu en crées une deuxième, donc il y a un moment où tu as les deux en mémoire.

    Les images prennent beaucoup de place. Le stockage le plus habituel utilise 4 octets pour un seul pixel (un octet par composante Rouge, Vert, Bleu, Alpha). Sur un iPad Retina, un écran prend donc 2048*1536*4 = 12 Mo.
  • CéroceCéroce Membre, Modérateur
    Ce que je te conseille dans un premier temps, c'est de lancer une analyse statique dans Xcode. ça va t'indiquer des endroits que le compilateur considère comme bizarre. Même si tu sais ce que tu fais dans ton code, ça peut être intéressant de corriger pour ne plus avoir aucune remarque à  l'analyse statique.

    Ensuite, lance Instruments avec l'instruments Leaks: il te signalera les endroits où des objets ne sont jamais libérés. C'est là -dessus que tu dois te concentrer.
  • busterTheobusterTheo Membre
    mars 2016 modifié #6

    ouais, ça doit être parce que je ne comprend pas trop ça :



    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    image.drawInRect(imageRect)
    let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    C'est bien là  que tu dis que je crée une seconde image ?


    Mais alors comment je fais pour redimensionner une image sans utiliser ce processus ?


  • busterTheobusterTheo Membre
    mars 2016 modifié #7

    Ah j'ai jamais fait (enfin, je ne m'en souviens plus) d'analyse statique dans Xcode.


    J'essaie en ce moment. Merci pour ces conseils précieux.


     


    Ah, alors, dans Instruments, Leaks est plus important que Allocation ?


     


     


    Dans Xcode, quand je regarde la mémoire (côté gauche), ça monte depuis toujours grave, sans rarement redescendre...


  • busterTheobusterTheo Membre
    mars 2016 modifié #8

    Heu je viens de faire "Analyze" dans Xcode, et il me dit "Succeeded". Donc tout va bien, ou il faut aller chercher quelque part son bilan ?


  • Joanna CarterJoanna Carter Membre, Modérateur


    Ah, alors, dans Instruments, Leaks est plus important que Allocation ?




    Oui.

  • Merci.


     


    Ah, j'ai trouvé cela pour "Analyze". Je m'y plonge... Désolé.


  • Ah ben ils sont gentils chez Apple.



    Note that if the static analyzer reports no problems, you can't assume that there are none. The tool cannot necessarily detect all the flaws in the source code.

    Donc, il y a d'indiqué, après avoir terminé "Analyze", en haut de mon projet "succeeded", et ça ne veut rien dire. J'ai surement plein de problèmes... Je ne comprend pas à  quoi ça sert le "Analyze"...

  • MalaMala Membre, Modérateur


    Ah ben ils sont gentils chez Apple.



    Note that if the static analyzer reports no problems, you can't assume that there are none. The tool cannot necessarily detect all the flaws in the source code.

    Donc, il y a d'indiqué, après avoir terminé "Analyze", en haut de mon projet "succeeded", et ça ne veut rien dire. J'ai surement plein de problèmes... Je ne comprend pas à  quoi ça sert le "Analyze"...




    Normal l'analyseur static est loin de pouvoir tout voir. Un cas typique c'est des objets qui se retiennent mutuellement. La fuite ne peut être constatée qu'à  l'exécution.

  • DrakenDraken Membre
    mars 2016 modifié #13


    ouais, ça doit être parce que je ne comprend pas trop ça :



    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    image.drawInRect(imageRect)
    let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    C'est bien là  que tu dis que je crée une seconde image ?




    C'est là  que tu crées une seconde et une TROISIEME image ! Heureusement l'une des deux est détruite après le processus. 



    // Création d'un contexte graphique de taille Size.
    // C'est un buffet vide avec la même occupation mémoire qu'une image de taille Size.
    UIGraphicsBeginImageContextWithOptions(size, false, 0)

    // Affichage de imageRect dans le contexte graphique
    // Cela ne consomme rien, la mémoire étant déjà  allouée à  la ligne précédente
    image.drawInRect(imageRect)

    // Création d'une nouvelle image
    let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    // Le contexte graphique est détruit à  sa fermeture, ce qui permet à  iOS
    // de récupérer la mémoire qu'il occupait.
    // L'image tampon est détruite (ouf!).
    //



  • busterTheobusterTheo Membre
    mars 2016 modifié #14

    Ah ok, merci Mala.


     


    Donc je fonce chez Mr Leaks.




  • Normal l'analyseur static est loin de pouvoir tout voir. Un cas typique c'est des objets qui se retiennent mutuellement. La fuite ne peut être constatée qu'à  l'exécution.




    Ou alors quand le voisin du dessous vient tambouriner à  la porte.

  • busterTheobusterTheo Membre
    mars 2016 modifié #16

    Merci Draken, je comprend encore moins.


    Donc, mon code craint. Il crée une seconde puis une troisième image.


    Et après, tu dis cela :



     


     


    // Le contexte graphique est détruit à  sa fermeture, ce qui permet à  iOS de récupérer la mémoire qu'il occupait (ouf !)

     


    Je dois comprendre quoi ?


    Le code est bon ou pas ?


    Et si non, faudrait faire quoi ?


     


     


    J'ai créé un second post pour ce sujet, pour ne pas polluer.


     


    Merci d'avance.


  • Oui, le code est bon ! On est obligé d'utiliser beaucoup de mémoire pour les traitements graphiques. C'est normal. D'ailleurs, si tu cherche sur le forum tu trouveras un exemple de code similaire écrit par Ali, c'est dire ..

  • Bon, concernant les histoires sur le scaledImage, j'ai la réponse de Draken dans ce post.


     


    Mais concernant l'histoire du window dans le AppDelegate, c'est ok ?


     


    Et pour le problème dans le configureNavBar, une idée ?


  • Concernant Instruments et la partie Allocations du lien, tu as zappé une partie importante.


     


    Il n'y a pas de problème en soit sur les allocations.


    En général, le problème, ce sont les fuites mémoires (Leaks). C'est à  dire des objets qui restent en mémoire alors que tu n'en as plus besoin.


    Les allocations sont nécessaires, mais si les objets sont ensuite détruits au bon moment, il n'y a pas de soucis en soit.


    Après, il y a de l'optimisation possible : Tu vois un pic de 400k allocations, as-tu réellement besoin de tous ces objets ? Peux-tu les charger uniquement en fonction de tes besoins réels ? C'est plus le problème qui semblait être posé par l'auteur du lien.


    Le souci avec trop d'allocations, c'est que ton appareil est limité (même si au fur et à  mesure des versions il a de plus en plus de mémoire), il a besoin d'un minimum d'espace libre pour vivre, d'où un Memory Warning possible qui apparait dans les logs. Mais par exemple, si tu prends un gros jeu AAA qui consomme énormément, c'est normal qu'il consomme. Il faut juste qu'il libère au moment adéquat.


  • CéroceCéroce Membre, Modérateur
    mars 2016 modifié #21
    Pour compléter la réponse de Larme: il est indispensable de corriger toutes les fuites mémoires (Leaks).

    Comme il s'agit d'objets qui n'ont pas été libérés mais qui auraient dû l'être, il se crée une accumulation de ces objets inutiles en mémoire. Au bout d'un moment, la consommation mémoire peut devenir importante et aller jusqu'à  ce que iOS tue l'application.
  • Bonjour à  tous, merci pour vos remarque judicieuses.


     


    Je vais prendre le temps d'analyser tout ça, et je reviens au bar.


Connectez-vous ou Inscrivez-vous pour répondre.