A propos des sites "updatables" (long)

Le
Damien Pinauldt
Bonjour,

(tout ce qui suit concerne à priori .Net2)
Après quelques jours passés à étudier de très près la réflexion, une
question me hante : faut-il craindre des memory leaks avec les sites que
l'on peut mettre à jour ?

Rappel :
Une application .Net quelle qu'elle soit, se divise en AppDomains. Un
AppDomain est une façon légère de décrire un contexte d'éxecution, plus
légère en tout cas qu'un processus (lourd !). Une application WinForm
classique contient au moins un AppDomain, créé par le runtime à son
démarrage.

C'est dans l'AppDomain que sont chargés les Assemblies, c'est à dire les
types définis dans le code et compilés en langage intermédiaire.
L'Assembly peut être un .exe ou une .dll, cela ne fait aucune différence
(en tout cas pour mon histoire).
Les génériques (List<Truc>) et les types intercédés (graphes DOM, Emit)
sont des cas un peu spéciaux, bref.
Sans parler de .Net3 (oups, trop tard)

Il n'est pas (à ma connaissance) possible de décharger un type ou un
assembly en particulier ; et c'est normal :
Que se passerait-il par exemple s'il y avait un constructeur statique ?
Il serait executé plusieurs fois dans le même contexte d'execution
(AppDomain), ce qui n'aurait évidement aucun sens. D'infinis autres
problèmes complexifieraient la tâche par ailleurs. Donc, tenons pour
acquis qu'on ne peut décharger ni un type, ni un assembly déjà chargé et
utilisé.

Donc, le principe, c'est que si l'on veut pouvoir changer un type (une
classe par exemple) pour une raison quelconque, il va falloir le prévoir.
Cela peut être parce que le client exige de pouvoir faire des mises à
jour de l'application sans downtime, ou bien parce que l'on a du code
qui s'auto-modifie en fonction de fichiers de configs, ou que sais-je
encore.

Classiquement, cela se fait en créant des AppDomain supplémentaires,
nommés, qui vont servir d'hôtes pour les Assemblys qui contiennent les
types susceptibles d'être modifiés. La "communication" entre ces
nouveaux AppDomain et l'application "mère" se fera par des classes
proxies qui sont spécialement prévues par le framework.
(c'est assez spécialisé donc je passe, mais pensez au proxy d'un webservice)
Lorsqu'une classe, une méthode, ou quoi que ce soit doit être mis à
jour, on va clôturer l'AppDomain, se qui va décharger les Assemblys,
appeller les destructeurs statiques, faire une collecte profonde du GC,
et tout un tas d'autres nettoyages (dans le désordre).
Tout cela implique donc un coût qui n'est pas négligeable, mais
acceptable dans le concept.

Revenons au coeur du sujet :
Il est possible de déployer un site sous la forme de pages .aspx
couplées à du code behind (.aspx.cs dans mon cas), et de permettre la
mise à jour, c'est à dire la modification à la volée de ce code.
Chaque couple page/code behind est compilé dans une .dll séparée, au nom
imprononçable car généré.
Bien que j'exècre l'App_Code, on peut également y mettre de façon
répugnante des saletés non précompilées.
Je pense qu'une modification du web.config peut également impliquer la
recompilation du site, mais je n'en suis pas sûr.

Vous voyez probablement où je veux en venir :
Chaque page étant une classe, et même un Assembly entier, que se
passe-t'il lorsque je modifie un iota dans -disons- le Page_Load ?

Une solution serait de dire que chaque page (c'est à dire une classe qui
hérite de Page), serait membre de son propre AppDomain.
Je ne suis pas un pro de "ce qu'il y a sous le capot", mais ça me
semblerait bigrement compliqué ! Et surtout, totalement inefficace pour
99,99% des sites web.

Une autre possibilité serait que tous les Assemblies "updatables" soient
chargé dans un AppDomain prévu à cet effet.
Cela semble plus raisonnable que la solution précédente, mais dans ce
cas comment toute la "magie" nécessaire serait-elle cachée au
développeur ? Car les classes que j'utilise ne m'ont pas l'air d'être
"proxy-isées", à l'insu de mon plein grès qui plus est.
En plus, toute la recompilation JIT des pages qui n'ont pas été
modifiées serait à refaire.
Pas terrible, mais il y a pire : que se passerait'il si j'avais un
Thread en cours, quelque part loin de la page que je viens de modifier ?
Devrais-je attendre, probablement une plombe, qu'il se termine
(peut-être ?) ?
Ou devrais-je le "tuer", sous prétexte qu'il ne serait pas de la bonne
génération (selon mes critères ethnocentristes) ?

La solution la plus vraisemblable qui me vienne à l'idée, c'est
qu'ASP.Net ne s'attend pas à avoir de nombreuses modifications, et que
donc il garde tout simplement des copies versionnées des pages au fur et
à mesure de leur recompilation. Et que donc, au fil de l'eau, si le site
est peu ou mal pensé, une part de plus en plus grande de la mémoire sera
occupée par des types qui ne sont plus utilisés.
(et oui, tout ça pour ça !)

Comme cela me tracasse, je me demandais si quelqu'un pouvait apporter
une réponse plus courte que ma question.

Merci !
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Frédéric LAMBOUR
Le #12144841
Je vais juste te répondre ce que j'ai constaté (attentino je ne déploie
jamais un site autrement que sous forme de dll + page apsx comme sous vs
2003) :

- Chaque modif du web.config fais redémarrer ton application (les sessions
en cours sont donc perdu)
- Chaque mise à jour itou (car recomplilation JIT)

a+

"Damien Pinauldt" news: 4638d164$0$29895$
Bonjour,

(tout ce qui suit concerne à priori .Net2)
Après quelques jours passés à étudier de très près la réflexion, une
question me hante : faut-il craindre des memory leaks avec les sites que
l'on peut mettre à jour ?

Rappel :
Une application .Net quelle qu'elle soit, se divise en AppDomains. Un
AppDomain est une façon légère de décrire un contexte d'éxecution, plus
légère en tout cas qu'un processus (lourd !). Une application WinForm
classique contient au moins un AppDomain, créé par le runtime à son
démarrage.

C'est dans l'AppDomain que sont chargés les Assemblies, c'est à dire les
types définis dans le code et compilés en langage intermédiaire.
L'Assembly peut être un .exe ou une .dll, cela ne fait aucune différence
(en tout cas pour mon histoire).
Les génériques (List<Truc>) et les types intercédés (graphes DOM, Emit)
sont des cas un peu spéciaux, bref.
Sans parler de .Net3 (oups, trop tard...)

Il n'est pas (à ma connaissance) possible de décharger un type ou un
assembly en particulier ; et c'est normal :
Que se passerait-il par exemple s'il y avait un constructeur statique ? Il
serait executé plusieurs fois dans le même contexte d'execution
(AppDomain), ce qui n'aurait évidement aucun sens. D'infinis autres
problèmes complexifieraient la tâche par ailleurs. Donc, tenons pour
acquis qu'on ne peut décharger ni un type, ni un assembly déjà chargé et
utilisé.

Donc, le principe, c'est que si l'on veut pouvoir changer un type (une
classe par exemple) pour une raison quelconque, il va falloir le prévoir.
Cela peut être parce que le client exige de pouvoir faire des mises à jour
de l'application sans downtime, ou bien parce que l'on a du code qui
s'auto-modifie en fonction de fichiers de configs, ou que sais-je encore.

Classiquement, cela se fait en créant des AppDomain supplémentaires,
nommés, qui vont servir d'hôtes pour les Assemblys qui contiennent les
types susceptibles d'être modifiés. La "communication" entre ces nouveaux
AppDomain et l'application "mère" se fera par des classes proxies qui sont
spécialement prévues par le framework.
(c'est assez spécialisé donc je passe, mais pensez au proxy d'un
webservice)
Lorsqu'une classe, une méthode, ou quoi que ce soit doit être mis à jour,
on va clôturer l'AppDomain, se qui va décharger les Assemblys, appeller
les destructeurs statiques, faire une collecte profonde du GC, et tout un
tas d'autres nettoyages (dans le désordre).
Tout cela implique donc un coût qui n'est pas négligeable, mais acceptable
dans le concept.

Revenons au coeur du sujet :
Il est possible de déployer un site sous la forme de pages .aspx couplées
à du code behind (.aspx.cs dans mon cas), et de permettre la mise à jour,
c'est à dire la modification à la volée de ce code.
Chaque couple page/code behind est compilé dans une .dll séparée, au nom
imprononçable car généré.
Bien que j'exècre l'App_Code, on peut également y mettre de façon
répugnante des saletés non précompilées.
Je pense qu'une modification du web.config peut également impliquer la
recompilation du site, mais je n'en suis pas sûr.

Vous voyez probablement où je veux en venir :
Chaque page étant une classe, et même un Assembly entier, que se
passe-t'il lorsque je modifie un iota dans -disons- le Page_Load ?

Une solution serait de dire que chaque page (c'est à dire une classe qui
hérite de Page), serait membre de son propre AppDomain.
Je ne suis pas un pro de "ce qu'il y a sous le capot", mais ça me
semblerait bigrement compliqué ! Et surtout, totalement inefficace pour
99,99% des sites web.

Une autre possibilité serait que tous les Assemblies "updatables" soient
chargé dans un AppDomain prévu à cet effet.
Cela semble plus raisonnable que la solution précédente, mais dans ce cas
comment toute la "magie" nécessaire serait-elle cachée au développeur ?
Car les classes que j'utilise ne m'ont pas l'air d'être "proxy-isées", à
l'insu de mon plein grès qui plus est.
En plus, toute la recompilation JIT des pages qui n'ont pas été modifiées
serait à refaire.
Pas terrible, mais il y a pire : que se passerait'il si j'avais un Thread
en cours, quelque part loin de la page que je viens de modifier ?
Devrais-je attendre, probablement une plombe, qu'il se termine (peut-être
?) ?
Ou devrais-je le "tuer", sous prétexte qu'il ne serait pas de la bonne
génération (selon mes critères ethnocentristes) ?

La solution la plus vraisemblable qui me vienne à l'idée, c'est qu'ASP.Net
ne s'attend pas à avoir de nombreuses modifications, et que donc il garde
tout simplement des copies versionnées des pages au fur et à mesure de
leur recompilation. Et que donc, au fil de l'eau, si le site est peu ou
mal pensé, une part de plus en plus grande de la mémoire sera occupée par
des types qui ne sont plus utilisés.
(et oui, tout ça pour ça !)

Comme cela me tracasse, je me demandais si quelqu'un pouvait apporter une
réponse plus courte que ma question.

Merci !


Frédéric LAMBOUR
Le #12144831
Je vais juste te répondre ce que j'ai constaté (attention je ne déploie
jamais un site autrement que sous forme de dll + page apsx comme sous vs
2003) :

- Chaque modif du web.config fais redémarrer ton application (les sessions
en cours sont donc perdu)
- Chaque mise à jour itou (car recomplilation JIT)

a+

"Damien Pinauldt" news: 4638d164$0$29895$
Bonjour,

(tout ce qui suit concerne à priori .Net2)
Après quelques jours passés à étudier de très près la réflexion, une
question me hante : faut-il craindre des memory leaks avec les sites que
l'on peut mettre à jour ?

Rappel :
Une application .Net quelle qu'elle soit, se divise en AppDomains. Un
AppDomain est une façon légère de décrire un contexte d'éxecution, plus
légère en tout cas qu'un processus (lourd !). Une application WinForm
classique contient au moins un AppDomain, créé par le runtime à son
démarrage.

C'est dans l'AppDomain que sont chargés les Assemblies, c'est à dire les
types définis dans le code et compilés en langage intermédiaire.
L'Assembly peut être un .exe ou une .dll, cela ne fait aucune différence
(en tout cas pour mon histoire).
Les génériques (List<Truc>) et les types intercédés (graphes DOM, Emit)
sont des cas un peu spéciaux, bref.
Sans parler de .Net3 (oups, trop tard...)

Il n'est pas (à ma connaissance) possible de décharger un type ou un
assembly en particulier ; et c'est normal :
Que se passerait-il par exemple s'il y avait un constructeur statique ? Il
serait executé plusieurs fois dans le même contexte d'execution
(AppDomain), ce qui n'aurait évidement aucun sens. D'infinis autres
problèmes complexifieraient la tâche par ailleurs. Donc, tenons pour
acquis qu'on ne peut décharger ni un type, ni un assembly déjà chargé et
utilisé.

Donc, le principe, c'est que si l'on veut pouvoir changer un type (une
classe par exemple) pour une raison quelconque, il va falloir le prévoir.
Cela peut être parce que le client exige de pouvoir faire des mises à jour
de l'application sans downtime, ou bien parce que l'on a du code qui
s'auto-modifie en fonction de fichiers de configs, ou que sais-je encore.

Classiquement, cela se fait en créant des AppDomain supplémentaires,
nommés, qui vont servir d'hôtes pour les Assemblys qui contiennent les
types susceptibles d'être modifiés. La "communication" entre ces nouveaux
AppDomain et l'application "mère" se fera par des classes proxies qui sont
spécialement prévues par le framework.
(c'est assez spécialisé donc je passe, mais pensez au proxy d'un
webservice)
Lorsqu'une classe, une méthode, ou quoi que ce soit doit être mis à jour,
on va clôturer l'AppDomain, se qui va décharger les Assemblys, appeller
les destructeurs statiques, faire une collecte profonde du GC, et tout un
tas d'autres nettoyages (dans le désordre).
Tout cela implique donc un coût qui n'est pas négligeable, mais acceptable
dans le concept.

Revenons au coeur du sujet :
Il est possible de déployer un site sous la forme de pages .aspx couplées
à du code behind (.aspx.cs dans mon cas), et de permettre la mise à jour,
c'est à dire la modification à la volée de ce code.
Chaque couple page/code behind est compilé dans une .dll séparée, au nom
imprononçable car généré.
Bien que j'exècre l'App_Code, on peut également y mettre de façon
répugnante des saletés non précompilées.
Je pense qu'une modification du web.config peut également impliquer la
recompilation du site, mais je n'en suis pas sûr.

Vous voyez probablement où je veux en venir :
Chaque page étant une classe, et même un Assembly entier, que se
passe-t'il lorsque je modifie un iota dans -disons- le Page_Load ?

Une solution serait de dire que chaque page (c'est à dire une classe qui
hérite de Page), serait membre de son propre AppDomain.
Je ne suis pas un pro de "ce qu'il y a sous le capot", mais ça me
semblerait bigrement compliqué ! Et surtout, totalement inefficace pour
99,99% des sites web.

Une autre possibilité serait que tous les Assemblies "updatables" soient
chargé dans un AppDomain prévu à cet effet.
Cela semble plus raisonnable que la solution précédente, mais dans ce cas
comment toute la "magie" nécessaire serait-elle cachée au développeur ?
Car les classes que j'utilise ne m'ont pas l'air d'être "proxy-isées", à
l'insu de mon plein grès qui plus est.
En plus, toute la recompilation JIT des pages qui n'ont pas été modifiées
serait à refaire.
Pas terrible, mais il y a pire : que se passerait'il si j'avais un Thread
en cours, quelque part loin de la page que je viens de modifier ?
Devrais-je attendre, probablement une plombe, qu'il se termine (peut-être
?) ?
Ou devrais-je le "tuer", sous prétexte qu'il ne serait pas de la bonne
génération (selon mes critères ethnocentristes) ?

La solution la plus vraisemblable qui me vienne à l'idée, c'est qu'ASP.Net
ne s'attend pas à avoir de nombreuses modifications, et que donc il garde
tout simplement des copies versionnées des pages au fur et à mesure de
leur recompilation. Et que donc, au fil de l'eau, si le site est peu ou
mal pensé, une part de plus en plus grande de la mémoire sera occupée par
des types qui ne sont plus utilisés.
(et oui, tout ça pour ça !)

Comme cela me tracasse, je me demandais si quelqu'un pouvait apporter une
réponse plus courte que ma question.

Merci !


Publicité
Poster une réponse
Anonyme