Déverrouillage des octets [] automatiquement épinglés dans un serveur de socket .NET

J'ai un serveur de socket asynchrone. J'ai rencontré un problème où les clients problématiques et difficiles à reproduire des événements de réseau provoquent un nombre fou de byte [] pour être épinglé. Puisque tout le threading pour gérer les clients est implicite (j'utilise BeginAcceptClient, et j'utilise des callbacks au lieu de threads qui sont explicitement instanciés) je ne contrôle pas le processus d'épinglage. Par "filetage implicite", je veux dire les fils générés non par moi directement, mais par le runtime hébergeant mon application.

Quoi qu'il en soit, la réponse à cet article montre comment débloquer des objets. Est-il possible de surcharger l'arrière-plan épinglant si je continue et épingle mon octet [] moi-même, fait le BeginRead et le désengage pendant le nettoyage?

Merci.

2

2 Réponses

La réponse dans le message que vous avez lié est complètement faux (je viens de laisser un commentaire là-bas). Ce n'est que lorsque la dernière poignée d'épinglage (plus générale: épingler "raison" car il y a d'autres raisons que GCHandles) est supprimée que l'objet est détaché. Vous ne pouvez pas forcer le retrait. Ce serait terriblement dangereux. Vous pouvez utiliser du code managé sûr pour faire des choses dangereuses, ce qui est même un problème de sécurité!

Quoi qu'il en soit, cela n'a aucun sens que vous essayiez d'empêcher l'épinglage de l'objet. Même si c'était possible, ce qui n'est pas le cas, votre processus s'écraserait à des moments aléatoires! Socket repose sur l'épinglage pour la correction. Il ne le fait pas sans raison.

La solution est ailleurs:

  1. Créez tous les tampons au démarrage de l'application afin que tous les tampons soient contigus en mémoire. Utilisez un pool de mémoire tampon.
  2. Utilisez un petit nombre de tampons volumineux et attribuez-en des sections à des clients individuels.

Une petite remarque: l'épinglage est mis en œuvre différemment de ce que vous pensez. L'épinglage n'est pas un indicateur que vous pouvez activer et désactiver sur un objet. Lorsque vous épinglez quelque chose, rien de spécial ne se produit au début. Ce n'est que lorsque le GC fonctionne, le GC remarque qu'il y a des références avec la propriété spéciale qu'ils épinglent. Il empêche ensuite l'objet d'être déplacé.

4
ajouté
Génial merci.
ajouté l'auteur kmarks2, source

Je suggère que vous au lieu de se concentrer sur Pin/Unpin faire tous vos appels de socket à partir d'un AppDomain différent. Vous pouvez alors, lorsque vous êtes à un point «inactif/sécurisé», décharger et recharger ce AppDomain pour réinitialiser la mémoire dans un bon état.

1
ajouté
Il pourrait simplement faire un GC manuel qui effacerait également tous les tampons inutilisés. L'arrêt d'un domaine n'apporte aucune nouvelle fonctionnalité concernant GC. Le GC est un processus global.
ajouté l'auteur usr, source
Vous supposez qu'il y a des fuites de poignée. L'implémentation de BCL Socket n'en a sûrement aucune, et il ne se bloque pas. Quoi qu'il en soit, l'arrêt de l'appdomain déconnecte le socket.
ajouté l'auteur usr, source
Le GC est global du processus, mais l'effacement du AppDomain appelle tous les finaliseurs sur les éléments de ce domaine; l'un d'entre eux, espérons-le, peut appeler Free sur le GCHandle qui détient toujours le tampon. Cela dépend du code en question, mais cela peut libérer le tableau pour que le GC puisse le récupérer lors de son prochain balayage.
ajouté l'auteur GWLlosa, source
Je suis d'accord; l'arrêt de l'appDomain déconnectera la prise. Mais quelqu'un doit fuir quelque chose; Puisque la mémoire détachée que quelqu'un d'autre a épinglé est difficile/sujette à erreur, le plus proche que je pense que vous pouvez obtenir est de vider l'AppDomain pour espérer que quelqu'un d'autre est dans une meilleure position pour nettoyer les tampons. Ceci suppose que les tampons ne sont pas sous votre contrôle.
ajouté l'auteur GWLlosa, source