Il semble que les gens se soient lassés de la gestion manuelle de la mémoire, alors ils ont inventé la collecte des ordures et la vie était assez bonne. Mais qu'en est-il de tous les autres types de ressources? Des descripteurs de fichiers, des sockets ou même des données créées par l'utilisateur comme les connexions à la base de données?
Cela ressemble à une question naïve mais je ne trouve aucun endroit où quelqu'un l'ait posée. Prenons les descripteurs de fichiers. Supposons qu'un programme sache qu'il ne sera autorisé à disposer de 4000 fds qu'au démarrage. Chaque fois qu'il effectue une opération qui ouvrira un descripteur de fichier, que se passe-t-il s'il
- Vérifiez qu'il n'est pas sur le point de s'épuiser.
- Si c'est le cas, déclenchez le garbage collector, ce qui libérera un tas de mémoire.
- Si une partie de la mémoire libérée contenait des références aux descripteurs de fichiers, fermez-les immédiatement. Il sait que la mémoire appartenait à une ressource car la mémoire liée à cette ressource a été enregistrée dans un «registre de descripteurs de fichiers», faute de meilleur terme, lors de son ouverture.
- Ouvrez un nouveau descripteur de fichier, copiez-le dans une nouvelle mémoire, enregistrez cet emplacement de mémoire dans le «registre des descripteurs de fichier» et renvoyez-le à l'utilisateur.
Ainsi, la ressource ne serait pas libérée rapidement, mais elle le serait chaque fois que le gc s'exécutait, ce qui inclut au moins, juste avant que la ressource ne soit sur le point de s'épuiser, en supposant qu'elle ne soit pas entièrement utilisée.
Et il semble que cela serait suffisant pour de nombreux problèmes de nettoyage des ressources définies par l'utilisateur. J'ai réussi à trouver un seul commentaire ici qui fait référence à un nettoyage similaire à celui-ci en C ++ avec un thread qui contient une référence à une ressource et le nettoie lorsqu'il ne reste qu'une seule référence (à partir du thread de nettoyage), mais je peux ' t trouver aucune preuve qu'il s'agit d'une bibliothèque ou d'une partie d'une langue existante.
la source
Il existe de nombreuses techniques de programmation pour aider à gérer ces types de ressources.
Les programmeurs C ++ utilisent souvent un modèle appelé Resource Acquisition is Initialization , ou RAII pour faire court. Ce modèle garantit que lorsqu'un objet qui détient des ressources devient hors de portée, il ferme les ressources auxquelles il était attaché. Ceci est utile lorsque la durée de vie de l'objet correspond à une portée particulière dans le programme (par exemple, quand il correspond au moment où un cadre de pile particulier est présent sur la pile), donc il est utile pour les objets qui sont pointés par des variables locales (pointeur variables stockées sur la pile), mais pas très utile pour les objets pointés par des pointeurs stockés sur le tas.
Java, C # et de nombreux autres langages fournissent un moyen de spécifier une méthode qui sera invoquée lorsqu'un objet n'est plus actif et sur le point d'être collecté par le garbage collector. Voir, par exemple, les finaliseurs
dispose()
, et autres. L'idée est que le programmeur peut implémenter une telle méthode afin de fermer explicitement la ressource avant que l'objet ne soit libéré par le garbage collector. Cependant, ces approches ont certains problèmes, que vous pouvez lire ailleurs; par exemple, le garbage collector peut ne pas collecter l'objet bien plus tard que vous le souhaitez.C # et d'autres langages fournissent un
using
mot-clé qui aide à garantir que les ressources sont fermées une fois qu'elles ne sont plus nécessaires (donc n'oubliez pas de fermer le descripteur de fichier ou une autre ressource). C'est souvent mieux que de s'appuyer sur le ramasse-miettes pour découvrir que l'objet n'est plus vivant. Voir, par exemple, /programming//q/75401/781723 . Le terme général ici est une ressource gérée . Cette notion s'appuie sur RAII et les finaliseurs, les améliorant à certains égards.la source
Toute la mémoire est égale, si je demande 1K, peu m'importe d'où vient l'espace 1K dans l'espace d'adressage.
Lorsque je demande un descripteur de fichier, je veux un descripteur du fichier que je souhaite ouvrir. L'ouverture d'un descripteur de fichier sur un fichier bloque souvent l'accès au fichier par d'autres processus ou machine.
Par conséquent, les descripteurs de fichiers doivent être fermés dès qu'ils ne sont pas nécessaires, sinon ils bloquent les autres accès au fichier, mais la mémoire ne doit être récupérée que lorsque vous commencez à en manquer.
L'exécution d'une passe GC est coûteuse et n'est effectuée que «lorsque cela est nécessaire», il n'est pas possible de prédire quand un autre processus aura besoin d'un descripteur de fichier que votre processus peut ne plus utiliser, mais qu'il a toujours ouvert.
la source
Je suppose que la raison pour laquelle cela n'a pas été beaucoup abordé pour d'autres ressources est exactement parce que la plupart des autres ressources sont préférables d'être libérées dès que possible pour que quiconque puisse les réutiliser.
Notez bien sûr que votre exemple pourrait maintenant être fourni en utilisant des descripteurs de fichiers "faibles" avec les techniques GC existantes.
la source
Vérifier si la mémoire n'est plus accessible (et donc garantie de ne plus être utilisée) est assez simple. La plupart des autres types de ressources peuvent être gérées plus ou moins par les mêmes techniques (c'est-à-dire que l'acquisition de ressources est l'initialisation, RAII et son équivalent de libération lorsque l'utilisateur est détruit, ce qui le relie à l'administration de la mémoire). Faire une sorte de libération "juste à temps" est en général impossible (vérifiez le problème d'arrêt, vous devrez découvrir qu'une certaine ressource a été utilisée pour la dernière fois). Oui, parfois cela peut être fait automatiquement, mais c'est un cas beaucoup plus compliqué que la mémoire. Il repose donc principalement sur l'intervention de l'utilisateur.
la source