Sto utilizzando il modulo ctypes
in python per caricare una libreria c condivisa, che contiene l'archiviazione locale dei thread. È una libreria c piuttosto grande con una lunga storia, che stiamo cercando di rendere sicuri i thread. La libreria contiene molte variabili e statiche globali, quindi la nostra strategia iniziale per la sicurezza dei thread è stata quella di utilizzare l'archiviazione locale dei thread. Vogliamo che la nostra libarary sia indipendente dalla piattaforma e che stiamo compilando e testando la sicurezza dei thread sia su Ubuntu win32, win64 e 64-bit. Da un puro processo c non sembrano esserci problemi.Perdita di memoria quando si utilizza la libreria condivisa con archiviazione locale dei thread tramite ctypes in un programma python
Tuttavia in python (2.6 e 2.7) su win32 e su Ubuntu stiamo assistendo a perdite di memoria. Sembra che la memoria locale del thread non venga rilasciata correttamente quando un thread python termina. O almeno che in qualche modo il processo Python non è "consapevole" che la memoria viene liberata. Lo stesso problema si vede anche in un programma in C# su win32 in realtà, ma non è presente sulla nostra macchina per test server Win64 (anche in esecuzione python 2.7).
Il problema può essere riprodotto con un semplice esempio giocattolo come questo:
Creare un c-file contenente (su linux/unix
rimuovere __declspec(dllexport)
):
#include <stdio.h>
#include <stdlib.h>
void __declspec(dllexport) Leaker(int tid){
static __thread double leaky[1024];
static __thread int init=0;
if (!init){
printf("Thread %d initializing.", tid);
int i;
for (i=0;i<1024;i++) leaky[i]=i;
init=1;}
else
printf("This is thread: %d\n",tid);
return;}
Compila spirito MINGW
su Windows/gcc su linux come:
gcc -o leaky.dll
(o leaky.so
) -shared the_file.c
Su Windows abbiamo potuto compilare con Visual Studio, sostituendo __thread
con __declspec(thread)
. Tuttavia su win32 (fino a winXP credo), questo non funziona se la libreria deve essere caricata in runtime con LoadLibrary
.
Ora creare un programma di pitone come:
import threading, ctypes, sys, time
NRUNS=1000
KEEP_ALIVE=5
REPEAT=2
lib=ctypes.cdll.LoadLibrary("leaky.dll")
lib.Leaker.argtypes=[ctypes.c_int]
lib.Leaker.restype=None
def UseLibrary(tid,repetitions):
for i in range(repetitions):
lib.Leaker(tid)
time.sleep(0.5)
def main():
finished_threads=0
while finished_threads<NRUNS:
if threading.activeCount()<KEEP_ALIVE:
finished_threads+=1
thread=threading.Thread(target=UseLibrary,args=(finished_threads,REPEAT))
thread.start()
while threading.activeCount()>1:
print("Active threads: %i" %threading.activeCount())
time.sleep(2)
return
if __name__=="__main__":
sys.exit(main())
Questo è sufficiente per riprodurre l'errore. Importare esplicitamente il garbage collector, facendo un collect gc.collect()
all'avvio di ogni nuovo thread non aiuta.
Per un po 'ho pensato che il problema avesse a che fare con runtime incompatibili (python compilato con Visual Studio, la mia libreria con MINGW
). Ma il problema è anche su Ubuntu, ma non su un server Win64, anche quando la biblioteca è croce compilato con MINGW
.
speranza che chiunque può aiutare!
Cheers, Simon Kokkendorff, National Survey e Catasto di Danimarca.
consulta noti bug di pitone http://bugs.python.org/issue6627 http://bugs.python.org/issue3757 –
Potrebbe liberare le variabili che perde sul filo vicino in C? –
per risolvere questo problema, prova ad usare malloc e gratis per inizializzare e rimuovere l'array – pyCthon