6
votes

Gychandle pour obtenir l'adresse (pointeur) de .NET objet

J'ai réussi à obtenir l'adresse d'un objet .NET par xxx

et je peux rappeler l'objet par xxx eh bien, Le but est de stocker l'adresse dans une classe natale et d'avoir une information dont l'objet natif est relé à celui de .NET.
AFAIK L'adresse ne change pas à cause de l'allocage, est-elle vraie ou quelqu'un a une meilleure idée de servir mon objectif?

Merci


2 commentaires

est-il possible de définir la valeur de "objet épinglé" comme: gchandle.fromintptr (INTPTR (adresse)). cible = myNewObject ??


@Martinch: Je ne sais pas s'il est légal de définir la propriété cible . Pourquoi ne demandez-vous pas à cela?


4 Réponses :


1
votes

afaik L'adresse ne change pas à cause de l'allocage, est-ce vrai

L'adresse d'un objet géré fait change. Le collecteur des ordures est libre de déplacer des objets en mémoire. Lorsque le collecteur des ordures est exécuté, il recueille des objets inutilisés, puis réarrise les objets restants pour minimiser la taille globale du tas géré.

Quelqu'un a-t-il une meilleure idée de servir mon objectif?

Je ne suis pas sûr que vous trouverez un bon moyen de conserver un pointeur pour un objet géré pendant de longues périodes. Il est possible d'épingler des objets en mémoire et d'obtenir leur adresse de cette façon, mais en C #, il est possible d'imprimer des objets uniquement dans une seule méthode.

Cela aiderait si vous avez expliqué plus en détail ce que vous allez faire avec le pointeur une fois que vous l'avez.


0 commentaires

7
votes

Vous voudrez épingler le GCLANDLE pour arrêter l'objet en mouvement, car le GC déplace des objets autour, un pointeur impinquant pourrait donc devenir invalide. Pinning L'objet arrête le déplacement:

handle.Free();


3 commentaires

"Une instance avec des membres non primitive (non blittable) ne peut pas être épinglée." dit Microsoft. C'est pourquoi j'utilise faiblackresurrection


msdn.microsoft.com/en-us/library /1246YZ8F(V=VS.80).aspx et les erreurs du compilateur


Je pense qu'il a raison, il devrait être épinglé. Quoi de neuf avec FLITTABLE? Voir le commentaire sur MSDN "Si vous ne pouvez pas obtenir une poignée de GC épinglée pour une classe, vous manquez probablement de [Structlayout (Layoutkind. *)] Dans vos définitions de type."



6
votes

Comme Tim et Tecopoop ont souligné, Gchandle.Alloc peut empêcher la collecte des ordures, mais l'adresse d'objet réelle peut changer car GC peut déplacer l'objet à moins que vous n'engageez l'objet. En outre, votre code utilise gchandletype.weaktrackresurrection et cela n'empêcherait pas la collecte des ordures. gchandle.tointptr donnera une adresse de la poignée qui peut être trébuchée autour de l'appel non géré. L'adresse d'objet réelle sera donnée par addrofpinnedObject méthode.

a dit tout cela, IMO, votre code peut servir à associer l'objet .NET avec un objet non géré. C'est parce que gchandle.to/fromintptr vous récupérera correctement GCLANDLE et vous pouvez atteindre votre objet .NET via celui-ci (à condition que ce n'est pas une poubelle non collectée). IMO, il devrait être immatériel si l'adresse d'objet réelle avait changé ou non.


4 commentaires

Eh bien, j'ai testé le code avec la création de 10 mil d'objets entre le réglage et la variable d'adresse et surpris de voir qu'il n'a pas changé. En effet, il s'agissait de l'adresse de manipuler de l'objet comme vous l'avez dit. Alors, comment puis-je empêcher les objets de la collecte des ordures?


Pourquoi ne pas utiliser gchandletype.normal - cela empêcherait la collecte des ordures.


Sur les secondes pensées, il peut ne pas fonctionner - par exemple, si vous créez GCLANDLE dans une méthode, il est adressé via TOINTPTR et transmettez-le du code non géré, puis faites le gérant.free, car sa sortie d'une portée, alors l'appel libre ferait un objet éligible Gc. Si vous êtes dans un tel scénario, je dirais que vous pouvez créer un dictionnaire / liste statique à vos objets pour empêcher la collecte des ordures.


Je vais créer et tenir la variable Gchandle à l'intérieur de l'objet .NET. Donc, si l'objet reste, le manche restera également. J'ai utilisé Gchandletype.normal Type mais car les objets sont créés, la mémoire augmente régulièrement, car les poignées sont conservées en tant que membre de l'objet. Mais il est indispensable car les objets avec des types de poignée faibles sont sûrement collectés lors de la collecte de GC.Collection forcée.



2
votes

Qu'est-ce que vous obtenez n'est pas vraiment une adresse.

Comme vous le souhaitez, il semble agir comme une adresse la plupart du temps et vous pouvez rappeler l'objet, en utilisant gchandle.fromintptr. Cependant, la question intéressante est que vous utilisez gchandletype.weaktrackresurrection .

Si votre objet faiblement référencé est collecté (il peut probablement, puisqu'il n'est faiblement référencé par le Gchandle), vous avez toujours le IntPTR et vous pouvez le transmettre à gchandle.fromintptr () . Si vous le faites, alors vous récupérez NULL, en supposant que le IntPTR n'a pas été recyclé.

(Si le INTPTR a été recyclé par le CLR pour une raison quelconque, vous avez des problèmes. Je ne sais pas si cela peut arriver.)

Vous ferez mieux d'utiliser gchandletype.normal ou gchandletype.pinned (si vous devez prendre l'adresse de l'objet dans le code non géré), si vous voulez une forte référence à l'objet.

(Pour utiliser Gchandletype.Pinked, votre objet doit être primitif ou avoir un attribut [StructLayout] ou être un tableau de tels objets.)


0 commentaires