-
[OSGi] Fuite mémoire
Bonjour à tous le monde;
Je viens chercher un peu d'aide sur le frameworks OSGI.
(Si je ne suis pas au bon endroit je laisse un modo déplacer le sujet où il doit être).
OSGI est un frameworks venant historiquement du monde de l'embarqué et de la domotique, industrie.
Maintenant il y a eu une démocratisation de ce frameworks qui permet de programmez d'une façon clairement orienté service avec un redéploiement à chaud des bundles. Chaque modification ne fait plus intervenir le redémarrage du serveur.
Je serais susceptible de développez en utilisant cette technologie mais en me renseignant je me suis aperçu que des utilisateurs se plaignaient de fuites mémoire saturant leur PermGen.
Mon problème est que pour la plupart ces remontées sont assez vieilles et ne précisent pas pourquoi ni si il y a moyen de contourner ce problème.
Pas plus que la source même du problème.
je voulais donc savoir si des personnes possédaient un peu plus de connaissance sur ce sujet?
Un grand merci à toute aide apportée
-
Les seuls problèmes de fuite mémoire que je connaisse ce sont les développeurs qui codent avec leurs pieds. C'est-à-dire qu'ils gardent une référence en dure fournie par un bundle sans écouter si le bundle est toujours actif.
-
Bon en toute honnête je suis loin d'être un expert en JAVA et encore plus loin de tout comprendre à OSGI.
Désolé si ce que je vais dire est complètement stupide.
:oops:
J'ai cru comprendre que justement les fuites mémoire sur OSGI ne sont pas forcément lié à une hypothétique incompétence des développeurs mais à des problèmes de librairies qui seraient invisible aux yeux du développeur.
En gros les références ne seraient pas dans le code même mais dans les librairies.
C'est idiot?
Sinon selon toi il n'y a aucun risque de fuites mémoires si le code est propre mais par contre il n'y pas de "mécanisme de défense" de la part d'OSGI pour éviter ces fuites lors de déploiement à chaud alors que c’est son principal objectif?
-
Les mécanismes de "défense" sont dans l'idiome pas dans l'implémentation.
Sinon il faudrait proxir toutes les instances échangées entre deux bundle, c'est possible, couteux et pas dans la philosophie OSGi.
Soit tu as une dépendance "forte"/explicite entre deux bundles (A dépend de B), tant que le bundle A n'est pas arrêté le bundle B ne peut l'être. Donc le bundle B n'est pas "récupérable". C'est un problème d'architecture.
Soit tu as une dépendance "faible"/implicite entre deux bundles.
Deux cas
1)
A récupère des instances de B. Si A ne surveille pas l'arrêt de B alors il va maintenir en mémoire des instances de B qui ne sont pas récupérable par la JVM tant que A les maintien. Pour peu que ces instances soient des classes de B, les ".class" restent également en mémoire, et le classloader pour B n'est lui même pas récupérable (idem encore pour les champs static).
Il est possible que A écoute les modifications de B mais que celui-ci fasse mal son nettoyage ... même problème.
2)
A injecte des instances dans B. Quand A s'arrête, il doit "retirer" ses instances sinon même problème que ci-dessus.
-
Ok merci beaucoup pour tes réponses.
Je comprends bien les problématiques que tu exposes. Ça parait facile et logique mais je me dis que si tu as un projet colossal avec des dizaines et des dizaines de bundles (développés par des personnes différentes) ça devient quand même très vite compliqué de prendre en compte toutes les dépendances que tu peux avoir. Surtout qu'encore une fois tu peux juste avoir des dépendances de librairie non?
C'est pour ça que je pensais qu'il pouvait y avoir un vrai mécanisme de protection contre ce type de problème quand on met en place un frameworks voulant apporter la modularité.
Bien sur que la solution n'est pas de faire en sorte d'avoir aucune dépendance vu que c'est ce qui fait la force d'OSGI.
Toutefois je pensais que l'interface Activator (responsable du cycle de vie) permettait de bien vérifier que toutes les instances étaient off avant de couper le bundle par exemple.
Pour résumer la seule solution de ne pas avoir de fuites mémoires sur OSGI c'est de développer de la manière la plus précautionneuse possible?
Encore merci pour tes retours
-
Les problèmes que j'ai mentionné ne sont pas spécifiques à OSGi loin de là !
Tu les retrouves même en C/C++ sous la forme de CoreDump ou autre Access memory violation.
La solution c'est de bien document les interface et que tout le monde respecte ce qui est documenté.
Si un bundle A injecte des instances dans B, il semble évident que celui-ci doit faire le ménage.
Si B accepte l'injection d'instance, il semble évident qu'il fournisse un service pour faire le ménage.
Si un bundle A récupère une instance fournie par B (sans nécessairement savoir qu'il s'agisse de B), la spécification/documentation du service doit indiquer si cette instance est susceptible ou pas d'être associée à un bundle.
Tâche aux implémentations des bundle A et B d'être en adéquation.
Pour comparer ces problèmes, restons dans un premier temps au Java. Si on prend Swing par exemple, il offre la possibilité d'attacher des listener aux composants. Ces listeners possèdent généralement une instance vers un manager quelconque de la logique applicative qui maintien lui même d'autres manager et données. Si tu "oublies" de retirer les listeners, le composant Swing maintient donc en mémoire le listener -> le manager -> autres managers et les données.
Dans l'exemple du C/C++, on prendra un manager A qui créée des instances et c'est donc logiquement lui qui va les détruire ; c'est une règle logique de responsabilité pour éviter les fuites mémoires. Bref, une partie B quelconque du programme récupère une instance auprès du manager la propage dans son sous-système. Puis vient l'ordre de supprimer la référence. La partie B gère proprement en surface mais n'a pas fait le ménage dans son sous-système ... Patatratra ... Au moment où le sous-système voudra accéder à la référence, l'adresse mémoire n'est plus réservée à notre application mais à une autre : CoreDump / Access memory violation.
Encore pire si c'est B qui s'autorise la responsabilité de supprimer la référence.
Il ne s'agit pas d'un problème de fuite mémoire mais l'inverse. Cependant la problématique est la même.
Pour avoir un vrai problème de fuite mémoire, ce serait la même chose qu'avant mais on estime qu'A n'a pas les moyens de savoir quand la référence doit être libérée et on assume que ce sont les utilisateurs de la classe A qui doive le faire. Seulement celui qui développe B n'a pas lu la documentation (ou est un débutant en C/C++) et ne libère pas les références qu'il récupère. Une fuite mémoire, une vraie.
Pour avoir le garde-fou que tu préconises, il y a deux choses :
Soit on "tag" les instances créées par un module comme ayant été créée pour un module particulier. Cependant ce n'est pas le fonctionnement mémoire de la JVM donc OSGi ne pourra rien à cela. Il faudrait également déterminer à quel "bundle" appartient chaque référence à une instance.
De plus cela voudrait dire qu'une String crée par un module bloquerait le module alors qu'il n'y a aucune dépendance. La String peut vivre sans B et B sans la String.
Soit on "proxy" les instances des classes d'un module dès lors qu'elles sortent du module. Idem il faut pouvoir déterminer à quel "bundle" appartient une référence vers une instance. Et cela changerait le comportement de l'opérateur "=". On pourrait supposer que les instances des classes d'un module A ne "sorte" du module uniquement depuis les services, il faudrait alors "proxir" les services pour "proxir" les réponses. Et que faire si un module A ayant récupérée une instance de B invoque une opération sur cette instance ? Il faudrait également "proxir" les instances renvoyées par cette même instance, etc.
-
Bon je pense que tout est dit.
Démonstration et argumentaire propre tu auras bien mérité ton "Résolu".:ccool:
Je te le dédicace!
Merci pour ton aide
-
Le résolu c'est pour le sujet, pour les utilisateurs ce sont les points.
L'argumentaire sans opposition reste un exercice facile, peut-être que le débat n'intéresse pas ou qu'il est évident ?
Tout l'argumentaire n'enlève pas le problème mais permet de l'éviter. Car bien documenter reste une tâche difficile et souvent dépréciée.
Bien coder ce qui est documenté (et surtout lire ce qui est documenté) peut parfois être complexe. Autant prévoir (suggérer) des solutions/implémentations au moment de concevoir/documenter l'interface du service.
Une fois la boulette mise en place, corriger le problème n'est pas moins complexe. Il y a même de quoi lancer un nouveau débat je pense.