Que sont exactement les ressources non gérées?


160

Je veux en savoir plus sur les ressources non gérées. Quelqu'un peut-il me donner une idée de base?


Voir également cette page, qui donne une explication et un modèle fantastiques pour l'utilisation correcte d'IDisposable, et comment prendre en compte les ressources non gérées: stackoverflow.com/questions/538060/…
Kyle Baran

Réponses:


177

Ressources gérées signifie essentiellement «mémoire gérée» gérée par le garbage collector. Lorsque vous n'avez plus de références à un objet géré (qui utilise la mémoire gérée), le garbage collector libèrera (éventuellement) cette mémoire pour vous.

Les ressources non gérées sont alors tout ce que le garbage collector ne sait pas. Par exemple:

  • Ouvrir des fichiers
  • Connexions réseau ouvertes
  • Mémoire non gérée
  • Dans XNA: tampons de vertex, tampons d'index, textures, etc.

Normalement, vous souhaitez libérer ces ressources non gérées avant de perdre toutes les références que vous avez à l'objet qui les gère. Vous faites cela en appelant Disposecet objet ou (en C #) en utilisant l' usinginstruction qui gérera l'appelDispose pour vous.

Si vous négligez de Dispose correctement vos ressources non gérées, le garbage collector finira par le gérer pour vous lorsque l'objet contenant cette ressource sera garbage collection (c'est la «finalisation»). Mais comme le garbage collector ne connaît pas les ressources non gérées, il ne peut pas dire à quel point il a besoin de les libérer - il est donc possible que votre programme fonctionne mal ou soit à court de ressources.

Si vous implémentez vous-même une classe qui gère des ressources non managées, c'est à vous de l'implémenter Disposeet Finalizecorrectement.


7
La connexion Open Database relève de quelle catégorie? Géré / non géré?
Deviprasad Das

8
+1 D'autres réponses manquent le point important que vous appelez Dispose sur un objet géré qui gère en interne la libération de la ressource non gérée qu'il encapsule (par exemple, descripteur de fichier, GDI + bitmap, ...) et que si vous accédez directement aux ressources non gérées ( PInvoke etc.) vous devez gérer cela.
Ian Mercer

2
@Dev: Non géré - car le GC ne le sait pas (en supposant que vous n'utilisez pas une base de données hypothétique en mémoire gérée). Mais l'objet de connexion lui - même peut ne pas contenir de ressource non gérée. Vraisemblablement, la connexion à la base de données utilise un fichier ouvert ou une connexion réseau quelque part - mais il est possible qu'un autre objet (autre que l'objet de connexion) gère cette ressource non gérée (peut-être que votre bibliothèque de base de données met en cache les connexions). Consultez la documentation et voyez où il vous demande d'appeler Disposeou d'utiliser using.
Andrew Russell

11
J'ai un commentaire / une question de base à ce sujet, puis-je relier un objet comme géré / non géré uniquement par le type, par exemple, la chaîne est gérée, DataSet n'est pas géré (c'est pourquoi il a une méthode Dispose ()) , Les connexions à la base de données ne sont pas gérées (car elles ont disposer), etc. Donc, si elle a une méthode "Dispose ()", elle n'est pas gérée? En plus de cela, que serait un objet XmlDocument? Merci
ganders

15
@ganders C'est une bonne règle de base. N'oubliez pas que toutes les instances de classe C # sont des objets gérés. Si une instance d'une classe peut contenir des ressources non gérées, alors cette classe doit être implémentée IDisposable. Si une classe ne mettre en œuvre IDisposable, vous devez disposer des instances de cette classe avec usingou Dispose()lorsque vous avez terminé avec eux. Sur cette base, votre réciproque tient: si une classe implémente IDisposable, elle contient probablement des ressources non gérées en interne.
Andrew Russell

56

Certains utilisateurs classent les fichiers ouverts, les connexions db, la mémoire allouée, les bitmaps, les flux de fichiers, etc. parmi les ressources gérées, d'autres parmi les ressources non gérées. Alors sont-ils gérés ou non gérés?

Mon opinion est que la réponse est plus complexe: lorsque vous ouvrez un fichier dans .NET, vous utilisez probablement une classe .NET intégrée System.IO.File, FileStream ou autre. Comme il s'agit d'une classe .NET normale, elle est gérée. Mais c'est un wrapper, qui à l'intérieur fait le "sale boulot" (communique avec le système d'exploitation en utilisant des dll Win32, appelant des fonctions de bas niveau ou même des instructions d'assembleur) qui ouvre vraiment le fichier. Et c'est ce que .NET ne sait pas, non géré. Mais vous pouvez peut-être ouvrir le fichier vous-même à l'aide des instructions de l'assembleur et contourner les fonctions de fichier .NET. Ensuite, le handle et le fichier ouvert sont des ressources non gérées.

La même chose avec la base de données: si vous utilisez un assemblage de base de données, vous avez des classes comme DbConnection etc., elles sont connues de .NET et gérées. Mais ils encapsulent le "sale boulot", qui n'est pas géré (allouer de la mémoire sur le serveur, établir une connexion avec lui, ...). Si vous n'utilisez pas cette classe wrapper et ouvrez vous-même une socket réseau et communiquez avec votre propre base de données étrange à l'aide de certaines commandes, elle n'est pas gérée.

Ces classes wrapper (File, DbConnection etc.) sont gérées, mais elles utilisent à l'intérieur des ressources non managées de la même manière que vous, si vous n'utilisez pas les wrappers et faites le "sale boulot" par vous-même. Et par conséquent, ces wrappers implémentent les modèles Dispose / Finalize. Il est de leur responsabilité de permettre au programmeur de libérer des ressources non gérées lorsque le wrapper n'est plus nécessaire, et de les libérer lorsque le wrapper est récupéré. L'encapsuleur sera correctement récupéré par garbage collector, mais les ressources non managées à l'intérieur seront collectées à l'aide du modèle Dispose / Finalize.

Si vous n'utilisez pas de classes d'encapsulation .NET ou tierces intégrées et que vous ouvrez des fichiers par des instructions d'assembleur, etc. dans votre classe, ces fichiers ouverts ne sont pas gérés et vous DEVEZ implémenter le modèle de disposition / finalisation. Si vous ne le faites pas, il y aura une fuite de mémoire, une ressource verrouillée à jamais, etc. même si vous ne l'utilisez plus (opération de fichier terminée) ou même après la fin de votre application.

Mais votre responsabilité est également lors de l'utilisation de ces emballages. Pour ceux qui implémentent disposer / finaliser (vous les reconnaissez, qu'ils implémentent IDisposable), implémentez également votre modèle de disposition / finalisation et supprimez même ces wrappers ou donnez-leur le signal de libérer leurs ressources non gérées. Si vous ne le faites pas, les ressources seront libérées après un certain temps indéfini, mais il est propre de le libérer immédiatement (fermez le fichier immédiatement et ne le laissez pas ouvert et bloqué pendant plusieurs minutes / heures au hasard). Ainsi, dans la méthode Dispose de votre classe, vous appelez les méthodes Dispose de tous vos wrappers utilisés.


1
Bon sur la clarté supplémentaire surunmanaged vs managed resources
maintenant celui qui ne doit pas être nommé.

merci pour votre réponse. sur quelles classes est-il recommandé d'appeler Dispose?
BKSpurgeon

2
C'est simple. Sur chaque classe que vous utilisez, vous devez vérifier si elle implémente l'interface IDisposable. Si oui, alors si vous utilisez une telle classe dans une méthode (par exemple: ouvrir un fichier, stocker du texte, fermer le fichier), vous pouvez utiliser ce modèle using () {}, qui appelle Dispose automatiquement pour vous. Si vous utilisez une telle classe dans plusieurs méthodes (par exemple: votre classe contient File, dans le constructeur elle ouvre le fichier, puis plusieurs méthodes ajoutent des logs ...), alors vous devez implémenter l'interface IDisposable par votre classe, implémenter le modèle Dispose / Finalize et disposer correctement des objets de cette classe.
Martas

1
"... une classe .NET intégrée System.IO.File, FileStream ou autre chose. Comme il s'agit d'une classe .NET normale, elle est gérée." Avec égards, c'est faux et trompeur. Ils ne sont pas gérés . Si elles étaient gérées, vous pourriez allouer ces classes et vous attendre à ce que le garbage collector gère entièrement la désallocation de toutes les ressources de manière déterministe. Cependant, cela entraînera le verrouillage et la conservation des descripteurs de fichiers et des ressources non gérées beaucoup plus longtemps que nécessaire, car le garbage collector ne désallouera pas la classe et ne la finalisera pas pendant une période potentiellement très longue.
AaronLS

1
@AaronLS dans votre commentaire, vous avez parlé de «FileStream» en le qualifiant de non géré, mais ce n'est pas le cas, bien qu'en interne, il utilise des ressources non gérées pour faire son travail.Dans le monde géré, Microsoft vous a caché beaucoup de jeter le motif. Le code géré ne signifie pas qu'il n'utilise pas de ressources non gérées. Cependant, Microsoft a fait du bon travail en implémentant IDisposable sur ces types d'objets. Ceci est démontré par le fait qu'il implémente IDisposable. En ce qui concerne cette preuve, nous devons la considérer comme un objet géré.
Malik Khalil

12

Les ressources non gérées sont celles qui s'exécutent en dehors du runtime .NET (CLR) (aka code non-.NET). Par exemple, un appel à une DLL dans l'API Win32 ou un appel à un .dll écrit en C ++.


6

Une "ressource non gérée" n'est pas une chose, mais une responsabilité. Si un objet possède une ressource non gérée, cela signifie que (1) une entité en dehors de lui a été manipulée d'une manière qui peut causer des problèmes si elle n'est pas nettoyée, et (2) l'objet a les informations nécessaires pour effectuer un tel nettoyage et est responsable pour le faire.

Bien que de nombreux types de ressources non gérées soient très fortement associés à divers types d'entités du système d'exploitation (fichiers, descripteurs GDI, blocs de mémoire alloués, etc.), il n'y a pas un seul type d'entité qui soit partagé par tous, à l'exception de la responsabilité de nettoyer. En règle générale, si un objet a la responsabilité d'effectuer le nettoyage, il aura une méthode Dispose qui lui demande d'effectuer tous les nettoyages dont il est responsable.

Dans certains cas, les objets tiennent compte de la possibilité qu'ils soient abandonnés sans que personne n'ait d'abord appelé Dispose. Le GC permet aux objets de demander une notification indiquant qu'ils ont été abandonnés (en appelant une routine appelée Finalize), et les objets peuvent utiliser cette notification pour effectuer eux-mêmes le nettoyage.

Des termes tels que «ressource gérée» et «ressource non gérée» sont malheureusement utilisés par différentes personnes pour désigner des choses différentes; Je pense franchement qu'il est plus utile de penser en termes d'objets comme n'ayant aucune responsabilité de nettoyage, ayant une responsabilité de nettoyage qui ne sera prise en charge que si Dispose est appelé, ou une responsabilité de nettoyage qui devrait être prise en charge via Dispose, mais qui peut également être pris en charge par Finalize.


5

La différence fondamentale entre une ressource gérée et non gérée est que le garbage collector connaît toutes les ressources gérées, à un moment donné, le GC viendra nettoyer toute la mémoire et les ressources associées à un objet géré. Le GC ne connaît pas les ressources non gérées, telles que les fichiers, les flux et les descripteurs, donc si vous ne les nettoyez pas explicitement dans votre code, vous vous retrouverez avec des fuites de mémoire et des ressources verrouillées.

Volé d' ici , n'hésitez pas à lire l'article en entier.


2

Toute ressource pour laquelle de la mémoire est allouée dans le tas managé .NET est une ressource gérée. CLR est parfaitement conscient de ce type de mémoire et fera tout pour s'assurer qu'il ne devienne pas orphelin. Tout le reste n'est pas géré. Par exemple, l'interopérabilité avec COM peut créer des objets dans l'espace mémoire de processus, mais CLR ne s'en chargera pas. Dans ce cas, l'objet géré qui effectue des appels au-delà de la limite gérée doit assumer la responsabilité de tout ce qui se trouve au-delà.


0

Voyons d'abord comment les programmes VB6 ou C ++ (applications non Dotnet) s'exécutaient. Nous savons que les ordinateurs ne comprennent que le code au niveau de la machine. Le code au niveau de la machine est également appelé code natif ou binaire. Ainsi, lorsque nous exécutons un programme VB6 ou C ++, le compilateur de langage respectif compile le code source du langage respectif en code natif, qui peut ensuite être compris par le système d'exploitation et le matériel sous-jacents.

Le code natif (code non managé) est spécifique (natif) du système d'exploitation sur lequel il est généré. Si vous prenez ce code natif compilé et essayez de l'exécuter sur un autre système d'exploitation, il échouera. Donc le problème avec ce style d'exécution de programme est qu'il n'est pas portable d'une plateforme à une autre.

Voyons maintenant comment s'exécute un programme .Net. En utilisant dotnet, nous pouvons créer différents types d'applications. Quelques-uns des types courants d'applications .NET incluent les applications Web, Windows, console et mobiles. Quel que soit le type de l'application, lorsque vous exécutez une application .NET, les événements suivants se produisent

  1. L'application .NET est compilée en langage intermédiaire (IL). IL est également appelé langage intermédiaire commun (CIL) et langage intermédiaire Microsoft (MSIL). Les applications .NET et non .NET génèrent un assembly. Les assemblys ont une extension .DLL ou .EXE. Par exemple, si vous compilez une application Windows ou Console, vous obtenez un .EXE, alors que lorsque nous compilons un projet de bibliothèque Web ou de classe, nous obtenons un .DLL. La différence entre un assembly .NET et NON .NET est que, l'assembly DOTNET est au format de langage intermédiaire alors que l'assembly NON DOTNET est au format de code natif.

  2. Les applications NON DOTNET peuvent s'exécuter directement sur le système d'exploitation, alors que les applications DOTNET s'exécutent sur un environnement virtuel appelé Common Language Runtime (CLR). CLR contient un composant appelé Just In-Time Compiler (JIT), qui convertira le langage intermédiaire en code natif que le système d'exploitation sous-jacent peut comprendre.

Ainsi, dans .NET, l'exécution de l'application se compose de 2 étapes 1. Le compilateur de langage, compile le code source en langage intermédiaire (IL) 2. Le compilateur JIT dans CLR convertit, l'IL en code natif qui peut ensuite être exécuté sur le système d'exploitation sous-jacent .

Étant donné qu'un assembly .NET est au format Intermedaite Language et non en code natif, les assemblys .NET sont portables sur n'importe quelle plate-forme, à condition que la plate-forme cible dispose du Common Language Runtime (CLR). Le CLR de la plate-forme cible convertit le langage Intermedaite en code natif que le système d'exploitation sous-jacent peut comprendre. L'intermédiaire Languge est également appelé code managé. C'est parce que CLR gère le code qui s'exécute à l'intérieur. Par exemple, dans un programme VB6, le développeur est responsable de la désallocation de la mémoire consommée par un objet. Si un programmeur oublie de désallouer de la mémoire, il se peut que nous ayons du mal à détecter les exceptions de mémoire. D'un autre côté, un programmeur .NET n'a pas à se soucier de la désallocation de la mémoire consommée par un objet. La gestion automatique de la mémoire, également appelée grabage collection, est fournie par CLR. Une part, du garbage collection, il existe plusieurs autres avantages fournis par le CLR, dont nous discuterons dans une session ultérieure. Puisque CLR gère et exécute le langage intermédiaire, il (IL) est également appelé code managé.

.NET prend en charge différents langages de programmation tels que C #, VB, J # et C ++. C #, VB et J # peuvent uniquement générer du code managé (IL), alors que C ++ peut générer à la fois du code managé (IL) et du code non managé (code natif).

Le code natif n'est stocké en permanence nulle part, après la fermeture du programme, le code natif est jetéa. Lorsque nous exécutons à nouveau le programme, le code natif est à nouveau généré.

Le programme .NET est similaire à l'exécution du programme Java. En java, nous avons des codes d'octet et JVM (Java Virtual Machine), où, comme dans .NET, nous avons un langage intermédiaire et CLR (Common Language Runtime)

Ceci est fourni à partir de ce lien - C'est un excellent tuteur. http://csharp-video-tutorials.blogspot.in/2012/07/net-program-execution-part-1.html

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.