¿Formas de liberar la memoria de vuelta al sistema operativo desde Python?

Tengo un código que se parece a esto:

def memoryIntensiveFunction(x): largeTempVariable = Intermediate(x) processFunction(largeTempVariable,x) 

El problema es que la variable temp es algo así como 500 mb en un caso de prueba mío, pero ese espacio no se devuelve al sistema operativo cuando finaliza memoryIntensiveFunction . Lo sé porque los perfiles de memoria con la herramienta guppy dicen que largeTempVariable está liberado (es decir, dentro de Python), pero psutil muestra que no lo está. Supongo que estoy viendo los efectos descritos aquí . El problema es que este proceso es de larga duración (es decir, horas), memoryIntensiveFunction se ejecuta al principio y nunca más, por lo que es un inconveniente para mí tener que cargar los 500 mb durante horas.

Una solución que encontré aquí y aquí sugiere usar un proceso separado. El multiprocesamiento incurre en sus propios costos, pero valdría la pena en mi caso. Sin embargo, esto requeriría que las personas que llaman a la función de memoryIntensiveFunction refactorización reciban x como valor de retorno en lugar de verla modificada en su lugar. El verdadero asesino es que mi objeto x no es seleccionable (hace un uso intensivo de las extensiones de python boost). Sería mucho trabajo hacer x pickable.

¿Hay alguna opción que no esté considerando?

Esto parece lo suficientemente curioso como para que intente reproducir su problema, y ​​parece que la simple “del” era suficiente. Para demostrarlo, puede ejecutar el siguiente código:

 import itertools import pdb def test(): a = "a" for _ in itertools.repeat(None, 30): a += a pdb.set_trace() del a pdb.set_trace() test() 

Y en el primer punto de interrupción verás que usa aproximadamente 1 gb de ram (quieres la entrada de python3.3):

  Private + Shared = RAM used Program 4.0 KiB + 9.0 KiB = 13.0 KiB VisualGDB-DisownTTY-r1 4.0 KiB + 15.0 KiB = 19.0 KiB sharing-tests 4.0 KiB + 19.5 KiB = 23.5 KiB dhcpcd 4.0 KiB + 31.5 KiB = 35.5 KiB gdb 4.0 KiB + 36.0 KiB = 40.0 KiB vim [deleted] 4.0 KiB + 38.0 KiB = 42.0 KiB systemd-udevd 40.0 KiB + 10.0 KiB = 50.0 KiB init 24.0 KiB + 135.0 KiB = 159.0 KiB agetty (6) 12.0 KiB + 150.0 KiB = 162.0 KiB su (3) 88.0 KiB + 103.0 KiB = 191.0 KiB syslog-ng (2) 152.0 KiB + 55.0 KiB = 207.0 KiB crond 172.0 KiB + 81.0 KiB = 253.0 KiB python3.4 580.0 KiB + 220.5 KiB = 800.5 KiB sshd (3) 768.0 KiB + 932.0 KiB = 1.7 MiB bash (13) 2.8 MiB + 118.0 KiB = 2.9 MiB mongod 7.4 MiB + 109.0 KiB = 7.5 MiB tmux [deleted] (2) 1.0 GiB + 1.2 MiB = 1.0 GiB python3.3 --------------------------------- 1.0 GiB ================================= 

Y luego, en el segundo punto de interrupción, después de que eliminamos la variable, se libera la memoria:

  Private + Shared = RAM used Program 4.0 KiB + 9.0 KiB = 13.0 KiB VisualGDB-DisownTTY-r1 4.0 KiB + 15.0 KiB = 19.0 KiB sharing-tests 4.0 KiB + 19.5 KiB = 23.5 KiB dhcpcd 4.0 KiB + 31.5 KiB = 35.5 KiB gdb 4.0 KiB + 36.0 KiB = 40.0 KiB vim [deleted] 4.0 KiB + 38.0 KiB = 42.0 KiB systemd-udevd 40.0 KiB + 10.0 KiB = 50.0 KiB init 24.0 KiB + 135.0 KiB = 159.0 KiB agetty (6) 12.0 KiB + 150.0 KiB = 162.0 KiB su (3) 88.0 KiB + 103.0 KiB = 191.0 KiB syslog-ng (2) 152.0 KiB + 55.0 KiB = 207.0 KiB crond 172.0 KiB + 81.0 KiB = 253.0 KiB python3.4 584.0 KiB + 220.5 KiB = 804.5 KiB sshd (3) 768.0 KiB + 928.0 KiB = 1.7 MiB bash (13) 2.8 MiB + 118.0 KiB = 2.9 MiB mongod 5.1 MiB + 1.2 MiB = 6.3 MiB python3.3 7.4 MiB + 109.0 KiB = 7.5 MiB tmux [deleted] (2) --------------------------------- 20.3 MiB ================================= 

Ahora, si eliminamos la función “del” y establecemos un punto de interrupción justo después de test ():

 import itertools import pdb def test(): a = "a" for _ in itertools.repeat(None, 30): a += a pdb.set_trace() test() pdb.set_trace() 

La memoria no será liberada antes de que terminemos:

  Private + Shared = RAM used Program 4.0 KiB + 9.0 KiB = 13.0 KiB VisualGDB-DisownTTY-r1 4.0 KiB + 15.0 KiB = 19.0 KiB sharing-tests 4.0 KiB + 19.5 KiB = 23.5 KiB dhcpcd 4.0 KiB + 31.5 KiB = 35.5 KiB gdb 4.0 KiB + 36.0 KiB = 40.0 KiB vim [deleted] 4.0 KiB + 38.0 KiB = 42.0 KiB systemd-udevd 40.0 KiB + 10.0 KiB = 50.0 KiB init 24.0 KiB + 135.0 KiB = 159.0 KiB agetty (6) 12.0 KiB + 150.0 KiB = 162.0 KiB su (3) 160.0 KiB + 53.0 KiB = 213.0 KiB crond 172.0 KiB + 81.0 KiB = 253.0 KiB python3.4 628.0 KiB + 219.5 KiB = 847.5 KiB sshd (3) 836.0 KiB + 152.0 KiB = 988.0 KiB syslog-ng (2) 752.0 KiB + 957.0 KiB = 1.7 MiB bash (13) 2.8 MiB + 113.0 KiB = 2.9 MiB mongod 7.4 MiB + 108.0 KiB = 7.6 MiB tmux [deleted] (2) 1.0 GiB + 1.1 MiB = 1.0 GiB python3.3 --------------------------------- 1.0 GiB ================================= 

Así que mi sugerencia? Simplemente elimine el sucker después de haberlo usado, y no lo necesite más;)