IA en automatisation industrielle

Guide de l’article

Comment détecter les fuites de mémoire dans les scripts d'automatisation Edge avec Python tracemalloc

Apprenez à utiliser le module tracemalloc de Python pour identifier la croissance de la mémoire dans les scripts d'automatisation Edge longue durée et valider les correctifs en toute sécurité avec les simulations persistantes d'OLLA Lab.

Réponse directe

Pour détecter les fuites de mémoire dans les scripts d'automatisation industrielle longue durée, les ingénieurs doivent utiliser le module `tracemalloc` de Python afin de comparer les instantanés d'allocation mémoire au fil du temps. Exécuter ces tests sur des simulations persistantes d'OLLA Lab permet de rendre les fuites cachées plus observables avant le déploiement sur des appareils Edge physiques et des environnements de processus réels.

Ce à quoi cet article répond

Résumé de l’article

Pour détecter les fuites de mémoire dans les scripts d'automatisation industrielle longue durée, les ingénieurs doivent utiliser le module `tracemalloc` de Python afin de comparer les instantanés d'allocation mémoire au fil du temps. Exécuter ces tests sur des simulations persistantes d'OLLA Lab permet de rendre les fuites cachées plus observables avant le déploiement sur des appareils Edge physiques et des environnements de processus réels.

Les fuites de mémoire dans l'automatisation ne sont généralement pas un problème lié à Python dans l'absolu. Il s'agit d'un problème de durée d'exécution dans un système fonctionnant 24h/24 et 7j/7. Un script qui se comporte parfaitement pendant dix minutes peut échouer au bout de deux semaines, ce qui n'est pas une question philosophique lorsque le boîtier Edge alimente des historiens, des API, des alarmes ou des systèmes de supervision par IA.

Une idée reçue courante est que le ramasse-miettes (garbage collection) rend les services Python longue durée « autonettoyants ». Ce n'est pas le cas. Python récupère les objets qui ne sont plus référencés ; il ne sauve pas les conceptions qui maintiennent des références actives, laissent des sockets ouverts ou accumulent indéfiniment des threads et des tampons.

Lors d'un récent test de résistance de 48 heures sur un enregistreur de données OPC UA basé sur Python et connecté au préréglage de traitement de l'eau d'OLLA Lab, l'omission de fermer explicitement la boucle de connexion a produit une augmentation mesurée de la mémoire de 2,4 Mo/heure ; le même script ne montrait aucun défaut visible lors d'un test sur banc de 10 minutes. [Méthodologie : n=1 variante de script sous charge d'interrogation simulée continue, comparée au même script avec fermeture explicite de la connexion, fenêtre de 48 heures.] Cela soutient un point précis : les tests courts peuvent manquer une instabilité mémoire sur longue durée. Cela n'établit pas un taux de défaillance à l'échelle de l'industrie.

Pourquoi les scripts d'automatisation longue durée développent-ils des fuites de mémoire ?

Les scripts d'automatisation longue durée fuient de la mémoire car ils utilisent l'allocation dynamique dans des environnements qui ne s'arrêtent jamais vraiment. Les cycles de balayage (scan cycles) des automates programmables (PLC) sont déterministes par conception : la mémoire est allouée pour les tags, les blocs fonctionnels et les structures d'exécution de manière bornée. Python n'est pas construit sur ce modèle. Il alloue des objets selon les besoins, suit les références et s'appuie sur le ramasse-miettes pour récupérer ce qui n'est plus accessible.

Cette distinction est importante car l'automatisation Edge est de plus en plus hybride. L'automate exécute toujours le contrôle déterministe, tandis que Python sur un IPC ou une passerelle gère l'interrogation, la traduction de protocole, les appels API, l'analyse locale et parfois la logique d'IA de supervision. Une architecture utile, certes. Mais une architecture peu indulgente.

En pratique, les fuites apparaissent lorsque le script maintient des objets actifs plus longtemps que prévu. Les trois sources OT les plus courantes sont banales et coûteuses :

Les 3 sources les plus courantes de fuites de mémoire OT

Une quatrième catégorie mérite d'être mentionnée car elle se cache bien : la mise en tampon au niveau de la bibliothèque. La fuite ne se trouve pas toujours dans votre code ; parfois, votre code l'active simplement de manière répétée.

  1. Sockets non fermés Les sessions Ethernet/IP, Modbus TCP, OPC UA, MQTT ou HTTP qui sont ouvertes à plusieurs reprises mais ne sont pas fermées proprement accumuleront des ressources au fil du temps.
  2. Ajouts dans des listes globales Les valeurs de tags historiques, les événements d'alarme ou les charges utiles d'API stockés dans des listes ou des dictionnaires non bornés créent une croissance constante de la mémoire, à moins qu'une limite FIFO ou de rétention ne soit appliquée.
  3. Accumulation de threads ou de tâches Les nouveaux threads, tâches asynchrones ou travailleurs de nouvelle tentative lancés lors d'échecs de communication peuvent persister indéfiniment s'ils se bloquent ou ne sont jamais joints et nettoyés.

En quoi le comportement de la mémoire dans Python diffère-t-il d'un cycle de balayage d'automate ?

Python et les environnements d'exécution d'automates résolvent des problèmes différents et échouent différemment. Un cycle de balayage d'automate est conçu pour une exécution répétitive et bornée par rapport à des structures d'E/S et de mémoire connues. Python est conçu pour l'informatique à usage général, où les objets peuvent être créés, référencés, transmis, mis en cache et conservés de manière flexible.

Le contraste est clair : mémoire de balayage déterministe versus durée de vie dynamique des objets.

C'est pourquoi « il a fonctionné une fois » est presque dénué de sens pour la fiabilité Edge. Un ingénieur de mise en service ne validerait pas une séquence d'alternance de pompes avec une seule commande de démarrage pour considérer le travail comme terminé. Le logiciel mérite le même scepticisme.

C'est aussi là que le terme Simulation-Ready (prêt pour la simulation) nécessite une définition précise. Dans l'usage d'Ampergon Vallis, Simulation-Ready ne signifie pas « familier avec la syntaxe » ou « à l'aise dans un éditeur de code ». Cela signifie qu'un ingénieur peut prouver, observer, diagnostiquer et renforcer la logique liée au contrôle par rapport à un comportement de processus réaliste avant qu'elle n'atteigne un processus réel. La syntaxe est nécessaire. La déployabilité est le test.

Comment le module `tracemalloc` identifie-t-il la croissance de la mémoire dans Python ?

`tracemalloc` identifie la croissance de la mémoire en traçant les allocations mémoire de Python et en comparant des instantanés au fil du temps. Il se connecte à l'allocateur de Python et enregistre où les blocs ont été alloués, ce qui permet aux ingénieurs d'inspecter la croissance par fichier, numéro de ligne ou regroupement de traces.

Cela le rend utile pour le débogage OT car il répond à la seule question qui compte une fois que la mémoire commence à grimper : d'où provient la croissance ?

Un modèle de base simple ressemble à ceci :

import tracemalloc import time

tracemalloc.start()

snapshot1 = tracemalloc.take_snapshot()

time.sleep(3600) # Exécuter pendant 1 heure

snapshot2 = tracemalloc.take_snapshot() top_stats = snapshot2.compare_to(snapshot1, 'lineno')

print("[Top 5 des emplacements de croissance mémoire]") for stat in top_stats[:5]: print(stat)

Cela ne détecte pas tous les problèmes de mémoire possibles dans chaque couche de dépendance. Il suit les allocations gérées par Python, ce qui est généralement la première étape appropriée, mais pas le dernier mot. Si une extension C ou un pilote fuit en dehors de l'allocateur de Python, vous pourriez également avoir besoin d'outils au niveau du système d'exploitation.

Un modèle industriel plus utile consiste à prendre des instantanés périodiques avec une journalisation contrôlée :

import tracemalloc import time from datetime import datetime

tracemalloc.start(25) # stocker un historique de trace plus profond

baseline = tracemalloc.take_snapshot()

for cycle in range(1, 25): # exemple : 24 vérifications horaires time.sleep(3600)

current = tracemalloc.take_snapshot() stats = current.compare_to(baseline, 'lineno')

print(f"\n[Instantané {cycle}] {datetime.now().isoformat()}") for stat in stats[:10]: print(stat)

Le but n'est pas d'admirer le résultat. Le but est d'établir si la croissance de la mémoire est bornée, stable et attribuable.

Que prouve réellement `tracemalloc`, et que ne prouve-t-il pas ?

`tracemalloc` prouve que les allocations gérées par Python ont augmenté entre les instantanés et montre où cette augmentation est associée dans le code. Il ne prouve pas, en soi, que l'augmentation est nocive, permanente ou inacceptable sur le plan opérationnel.

Cette distinction est importante car toute croissance n'est pas une fuite. Une certaine croissance de la mémoire est attendue lors du démarrage, du préchauffage du cache, du chargement de modèles ou de l'initialisation par lots. Une fuite est mieux définie opérationnellement comme une croissance de la mémoire qui se poursuit sans plafond d'état stable justifié pendant le profil d'exécution prévu.

Pour l'automatisation Edge, le profil d'exécution prévu se mesure généralement en jours ou en semaines, pas en minutes.

Une règle de décision pratique est :

- Croissance attendue : augmente pendant le démarrage, puis se stabilise. - Croissance suspecte : augmente avec les pics de charge, puis récupère partiellement. - Comportement de fuite : augmente de façon monotone ou par paliers sans plateau significatif.

C'est pourquoi une paire d'instantanés est rarement suffisante. La tendance compte. Les défaillances industrielles sont souvent assez lentes pour passer un test de démonstration et assez rapides pour gâcher un week-end.

Comment tester les scripts Edge par rapport à des simulations d'automate longue durée ?

Vous testez les scripts Edge par rapport à des simulations d'automate longue durée en connectant le script à un processus virtuel persistant, en exécutant la charge de travail d'interrogation ou d'orchestration prévue pendant des heures ou des jours, et en comparant les instantanés de mémoire pendant que l'état du processus continue d'évoluer.

Le matériel physique n'est pas le premier endroit approprié pour ce test. Immobiliser un rack d'automate, des E/S distantes et des appareils de terrain pour un essai de stabilité logicielle de 48 ou 72 heures est coûteux, opérationnellement gênant et souvent impossible dans un environnement adjacent à la production. L'usine a généralement d'autres priorités.

C'est là qu'OLLA Lab devient opérationnellement utile. OLLA Lab est un simulateur de logique à contacts (ladder logic) et de jumeau numérique basé sur le Web qui permet aux ingénieurs de construire une logique, d'exécuter des simulations persistantes, d'inspecter les E/S et les variables, et de valider le comportement par rapport à des scénarios industriels réalistes. Dans ce contexte, sa valeur est bornée et pratique : il fournit un environnement persistant et à risque contenu pour la validation longue durée des logiciels côté Edge interagissant avec un comportement de contrôle simulé.

Opérationnellement, le flux de travail est simple :

  • Lancez un scénario OLLA Lab avec un comportement de processus stable, tel qu'une station de pompage, une centrale de traitement d'air CVC ou une séquence de traitement de l'eau.
  • Exécutez la logique à contacts en Mode Simulation.
  • Utilisez le Panneau des Variables pour confirmer les changements de tags, les valeurs analogiques, les sorties et les états de séquence.
  • Connectez le script Python externe à l'environnement de tags simulé ou au flux de travail d'E/S en miroir utilisé pour les tests.
  • Démarrez `tracemalloc`.
  • Laissez le script s'exécuter dans des conditions réalistes d'interrogation, de nouvelle tentative, de journalisation et de gestion des pannes pendant une période prolongée.

Le point important est la persistance. Une fuite qui apparaît après six heures est invisible dans un test de cinq minutes, et un jumeau numérique ne s'ennuie jamais.

Quel est le flux de travail pour déboguer une fuite de mémoire dans OLLA Lab ?

Le flux de travail pour déboguer une fuite de mémoire dans OLLA Lab consiste à établir une base de référence, induire une charge réaliste, comparer les instantanés de mémoire, isoler la cause, refactoriser le script et répéter la simulation jusqu'à ce que le comportement de la mémoire se stabilise.

Flux de travail de débogage étape par étape

  1. Établir la base de référence Ouvrez un préréglage industriel d'OLLA Lab tel qu'une centrale de traitement d'air CVC, une station de relevage ou un processus de traitement de l'eau. Démarrez la simulation et prenez un instantané `tracemalloc` initial avant que l'interrogation soutenue ne commence.
  2. Induire la charge Exécutez le script Python par rapport au processus simulé au taux de fonctionnement prévu. Par exemple, interrogez les tags toutes les 50 ms, écrivez les résultats dans un tampon local et déclenchez tous les appels API ou historiens normaux. Maintenez l'exécution pendant au moins quatre heures ; plus c'est long, mieux c'est lorsque le cycle de service de production est continu.
  3. Comparer les instantanés Utilisez `snapshot2.compare_to(snapshot1, 'lineno')` ou des comparaisons périodiques par rapport à la base de référence pour identifier quelles lignes ou modules accumulent de la mémoire.
  4. Inspecter le mode de défaillance Déterminez si la croissance provient de la gestion des connexions, des structures de données conservées, des nouvelles tentatives, des tâches asynchrones ou du comportement de la bibliothèque. C'est là que le jugement technique compte plus que la familiarité avec la syntaxe.
  5. Refactoriser et valider Fermez explicitement les sockets, implémentez des files d'attente bornées, joignez ou annulez les threads, réduisez la rétention d'objets ou révisez la logique de nouvelle tentative. Ensuite, relancez la même simulation OLLA Lab et confirmez que la croissance de la mémoire atteint un plafond stable ou reste effectivement plate.
  6. Documenter les preuves Conservez les deltas des instantanés avant/après, la durée d'exécution, le scénario simulé, l'intervalle d'interrogation et les notes de révision du code. Si le correctif ne peut pas être expliqué, il n'a pas vraiment été validé.

À quoi ressemble un modèle de fuite réel dans le code d'automatisation ?

Un modèle de fuite réel semble ennuyeux au début. C'est une partie du problème. Le script continue de collecter des données, le processus continue de bouger et la charge du système semble normale jusqu'à ce que la pression sur la mémoire dépasse un seuil et que tout se dégrade en même temps.

Considérez un anti-modèle simplifié :

import time data_log = []

while True: tag_values = read_plc_tags() # renvoie un dict des valeurs actuelles data_log.append(tag_values) # croissance non bornée send_to_api(tag_values) time.sleep(0.05)

Ce code peut être fonctionnellement correct et opérationnellement imprudent. Si le processus s'exécute en continu, `data_log` devient un puits de mémoire.

Une version bornée est plus sûre :

import time from collections import deque

data_log = deque(maxlen=2000)

while True: tag_values = read_plc_tags() data_log.append(tag_values) send_to_api(tag_values) time.sleep(0.05)

Le même principe s'applique aux connexions :

client = open_connection() while True: if need_refresh(): client = open_connection() # l'ancienne connexion peut persister poll(client)

Un modèle plus sûr utilise une gestion explicite du cycle de vie :

while True: with open_connection() as client: poll(client) process_data(client) sleep_interval()

L'implémentation exacte dépend de la bibliothèque, mais la règle ne change pas : la durée de vie des ressources doit être explicite dans le code OT longue durée.

Combien de temps un test de fuite de mémoire doit-il durer avant de pouvoir faire confiance au résultat ?

Un test de fuite de mémoire doit durer suffisamment longtemps pour couvrir le cycle de service prévu, le rythme de communication et le comportement de gestion des pannes du script déployé. En pratique, cela signifie généralement des heures au minimum et souvent 24 à 72 heures pour les charges de travail Edge fonctionnant en continu.

Il n'y a pas de durée magique universelle. Un script interrogeant chaque seconde avec des téléchargements par lots horaires a un profil de risque différent de celui interrogeant toutes les 50 ms avec des tempêtes de nouvelles tentatives sur des communications intermittentes. La durée du test doit être liée au comportement pertinent le plus lent du système.

Une approche technique raisonnable est :

- 1–2 heures : détecte une croissance incontrôlée évidente - 4–8 heures : détecte de nombreux problèmes de rétention et de mise en tampon - 24+ heures : commence à représenter un comportement en service continu - 48–72 heures : plus crédible pour les services Edge censés fonctionner sans surveillance

Le test doit également inclure des états anormaux, pas seulement un fonctionnement nominal. Un script qui survit à une interrogation en régime permanent mais fuit pendant des tempêtes de reconnexion est toujours un script qui fuit.

Comment les ingénieurs doivent-ils prouver qu'un script est réellement durci ?

Les ingénieurs doivent constituer un ensemble compact de preuves de validation, et non une galerie de captures d'écran. L'artefact doit montrer ce qui a été testé, ce que signifiait « correct », comment la défaillance a été induite et ce qui a changé après la révision.

Utilisez cette structure :

Définissez le succès en termes observables : mémoire stable sur une exécution de 24 heures, aucune croissance d'objet non bornée, comportement de reconnexion réussi et aucune perte des mises à jour de tags requises.

Indiquez la défaillance introduite ou observée : session OPC UA non fermée, liste d'événements non bornée, thread de nouvelle tentative bloqué ou boucle de reconnexion mal formée.

Documentez le changement de code ou d'architecture : fermeture explicite de socket, file d'attente bornée, backoff de nouvelle tentative, nettoyage de thread ou substitution de bibliothèque.

  1. Description du système Décrivez le processus simulé, le rôle de la logique à contacts, la fonction du script Edge, l'intervalle d'interrogation, les protocoles et la cible d'exécution.
  2. Définition opérationnelle de « correct »
  3. Logique à contacts et état de l'équipement simulé Enregistrez le scénario OLLA Lab, les états de séquence pertinents, les conditions analogiques, les conditions d'alarme et le contexte de logique à contacts avec lequel le script a interagi.
  4. Le cas de défaillance injecté
  5. La révision effectuée
  6. Leçons apprises Résumez ce que la défaillance a révélé sur les hypothèses d'exécution, l'interaction avec le processus et le risque de déploiement.

C'est le genre de preuve qui soutient une revue technique. Elle est également facile à partager entre les équipes car elle explique le comportement, pas seulement l'apparence.

Quel est le rapport avec les normes, la sécurité et le risque de mise en service ?

Le test de fuite de mémoire n'est pas la même chose que la validation de la sécurité fonctionnelle, mais c'est tout de même un problème de risque de mise en service. La norme IEC 61508 et les pratiques de sécurité connexes se concentrent sur l'intégrité systématique, la discipline du cycle de vie et le contrôle des défaillances dangereuses dans les systèmes électriques, électroniques et programmables. Un script Edge qui fuit peut se situer en dehors de la fonction de sécurité principale, tout en créant des risques opérationnels par perte de visibilité, alarmes retardées, décisions de supervision obsolètes ou intégrations défaillantes.

La distinction de sécurité est simple : tous les services Edge ne sont pas liés à la sécurité, mais tout service Edge instable est un risque pour la fiabilité.

La validation par jumeau numérique est utile ici car elle permet une exposition répétée à un comportement de processus réaliste sans nécessiter d'équipement réel. La littérature sur l'ingénierie basée sur la simulation et les systèmes cyber-physiques industriels soutient la valeur des environnements virtuels haute fidélité pour la validation, la formation des opérateurs et l'analyse des défaillances, à condition que les affirmations restent bornées à la tâche simulée plutôt que traitées comme une preuve universelle (Antonino et al., 2024 ; Tao et al., 2019 ; Villalonga et al., 2021).

Dans ce cadre, OLLA Lab doit être compris comme un environnement de validation et de répétition pour les tâches d'automatisation à haut risque. Ce n'est pas un substitut aux tests de réception sur site, au travail formel sur le cycle de vie de la sécurité ou à l'analyse des risques spécifique à l'usine.

Quand utiliser OLLA Lab plutôt que du matériel physique pour les tests de mémoire ?

Vous devez utiliser OLLA Lab plutôt que du matériel physique lorsque la question technique porte sur le comportement longue durée, la répétabilité, l'injection de pannes et la validation à faible risque des logiciels interagissant avec une logique de contrôle.

Cela inclut des cas tels que :

  • les enregistreurs de données Edge interrogeant des tags d'automate simulés en continu
  • les ponts de protocole déplaçant des données entre les systèmes OT et IT
  • les scripts d'orchestration connectés par API
  • les scripts de supervision assistés par IA qui observent l'état du processus et émettent des recommandations ou des commandes bornées
  • les répétitions de mise en service où la logique, l'état des E/S et les scénarios anormaux doivent être rejoués à plusieurs reprises

Le matériel physique reste important pour l'intégration finale, la validation du timing, le comportement spécifique à l'appareil et les contraintes environnementales. Mais le matériel est un mauvais endroit pour découvrir qu'une liste Python a augmenté silencieusement pendant 19 heures.

Conclusion

La réponse pratique est simple : si un script d'automatisation Python doit fonctionner en continu, `tracemalloc` doit faire partie du flux de travail de validation. Les tests sur banc courts n'établissent pas la stabilité de la mémoire, et les défaillances Edge causées par des fuites lentes sont exactement le genre de défaut qui survit aux tests superficiels.

Le modèle technique le plus robuste consiste à coupler `tracemalloc` avec un environnement de simulation persistant. Cette combinaison vous permet d'observer le comportement de la mémoire dans des conditions de processus réalistes, d'isoler la croissance sur des chemins de code spécifiques, de réviser la conception et de relancer la même charge de travail sans immobiliser d'actifs physiques.

C'est à cela que ressemble le travail Simulation-Ready en pratique : non pas simplement écrire du code qui s'exécute, mais prouver qu'il reste stable, observable et correct lorsque le processus continue de bouger.

Expert en automatisation industrielle et systèmes cyber-physiques, spécialisé dans l'optimisation des flux de travail Edge et la validation logicielle par simulation.

Cet article a été vérifié pour sa conformité technique avec les pratiques de débogage Python et les standards d'automatisation industrielle.

References

Transparence éditoriale

Cet article de blog a été rédigé par un humain, avec toute la structure de base, le contenu et les idées originales créés par l’auteur. Toutefois, cet article inclut un texte affiné avec l’assistance de ChatGPT et Gemini. L’IA a été utilisée exclusivement pour corriger la grammaire et la syntaxe, ainsi que pour traduire le texte original en anglais vers l’espagnol, le français, l’estonien, le chinois, le russe, le portugais, l’allemand et l’italien. Le contenu final a été relu, édité et validé de manière critique par l’auteur, qui en assume l’entière responsabilité quant à son exactitude.

À propos de l’auteur:PhD. Jose NERI, Lead Engineer at Ampergon Vallis

Vérification: Validité technique confirmée le 2026-03-23 par l’équipe QA du laboratoire Ampergon Vallis.

Prêt pour la mise en œuvre

Utilisez des workflows appuyés par la simulation pour transformer ces enseignements en résultats mesurables pour l’installation.

© 2026 Ampergon Vallis. All rights reserved.
|