J'utilise l'API C d'un fournisseur pour un logiciel métier en chargeant leur bibliothèque à l'aide du module ctypes de Python. Après le déploiement du logiciel que j'ai écrit, j'ai trouvé que la bibliothèque du fournisseur fuit la mémoire sur une base cohérente et prévisible, selon le nombre d'appels d'une certaine fonction qui fait partie de leur API.Comment contourner une fuite de mémoire dans la DLL d'un fournisseur utilisé en Python?
J'ai même dupliqué la fuite dans un programme C qui n'utilise aucune allocation de tas. J'ai contacté le vendeur à propos du problème, et ils ont dit qu'ils y travaillaient, mais je ne peux probablement pas attendre un correctif avant la prochaine version du logiciel.
J'ai eu l'idée de recharger la DLL du fournisseur après un certain seuil d'appels à la fonction de fuite, mais cela n'a pas libéré la mémoire qui a fui.
Je trouve que je pouvais forcer la bibliothèque à décharger comme ceci:
_ctypes.FreeLibrary(vendor_dll._handle)
Cela permet de libérer la mémoire, mais l'interpréteur crash apparemment au hasard après un certain nombre de minutes d'utilisation de l'API du fournisseur.
Je trouve cette question dans le bug tracker Python qui décrit ma situation: https://bugs.python.org/issue14597
Il semble que s'il y a encore une référence ouverte à la bibliothèque, le forçant à décharger va planter inévitablement l'interpréteur Python. Dans le pire des cas, je pense pouvoir charger la bibliothèque du fournisseur dans un processus séparé, demander des requêtes proxy à l'aide d'une file d'attente multiprocesseur et configurer un chien de garde pour recréer le processus si l'interpréteur meurt.
Y a-t-il une meilleure façon de contourner ce problème?
Je suppose qu'une solution plus élégante à ma solution de contournement ci-dessus serait de quitter et de relancer le processus de travail sur un intervalle régulier. Cela permettrait à la librairie libérée par la librairie du vendeur de se libérer, mais ne ferait pas planter l'interpréteur. – jakogut
Si libérer la bibliothèque fonctionne, ce n'est pas vraiment une fuite de mémoire. La bibliothèque doit suivre ces allocations pour les libérer sur 'DLL_PROCESS_DETACH'. En ce qui concerne le déchargement de 'vendor_dll', vous devez d'abord supprimer toutes les références à l'instance en cours et veiller à ce que rien ne répète son code, y compris les rappels asynchrones en attente. Ensuite, vous pouvez décharger et recharger la DLL. Les bibliothèques partagées sont comptées par référence, donc pour s'assurer qu'elles sont effectivement déchargées, appelez 'FreeLibrary' jusqu'à ce que cela déclenche un' OSError'. – eryksun