programas - ruby on rails download
¿Por qué este programa de Ruby no devuelve la memoria del montón al sistema operativo? (1)
Estoy tratando de entender cuándo la memoria asignada fuera del montón de Ruby se devuelve al sistema operativo. Entiendo que Ruby nunca devuelve la memoria asignada a su montón, pero todavía no estoy seguro sobre el comportamiento de la memoria fuera del montón. Es decir, aquellos objetos que no encajan en un RVALUE de 40 bytes.
Considere el siguiente programa que asigna algunas cadenas grandes y luego fuerza a un GC principal.
require ''objspace''
STRING_SIZE = 250
def print_stats(msg)
puts ''-------------------''
puts msg
puts ''-------------------''
puts "RSS: #{`ps -eo rss,pid | grep #{Process.pid} | grep -v grep | awk ''{ print $1,"KB";}''`}"
puts "HEAP SIZE: #{(GC.stat[:heap_sorted_length] * 408 * 40)/1024} KB"
puts "SIZE OF ALL OBJECTS: #{ObjectSpace.memsize_of_all/1024} KB"
end
def run
print_stats(''START WORK'')
@data=[]
600_000.times do
@data << " " * STRING_SIZE
end
print_stats(''END WORK'')
@data=nil
end
run
GC.start
print_stats(''AFTER FORCED MAJOR GC'')
Ejecutando este programa con Ruby 2.2.3 en MRI produce el siguiente resultado. Después de un GC importante forzado, el tamaño del montón es el esperado, pero el RSS no ha disminuido significativamente.
-------------------
START WORK
-------------------
RSS: 7036 KB
HEAP SIZE: 1195 KB
SIZE OF ALL OBJECTS: 3172 KB
-------------------
END WORK
-------------------
RSS: 205660 KB
HEAP SIZE: 35046 KB
SIZE OF ALL OBJECTS: 178423 KB
-------------------
AFTER FORCED MAJOR GC
-------------------
RSS: 164492 KB
HEAP SIZE: 35046 KB
SIZE OF ALL OBJECTS: 2484 KB
Compare estos resultados con los siguientes cuando asignamos un objeto grande en lugar de muchos objetos más pequeños.
def run
print_stats(''START WORK'')
@data = " " * STRING_SIZE * 600_000
print_stats(''END WORK'')
@data=nil
end
-------------------
START WORK
-------------------
RSS: 7072 KB
HEAP SIZE: 1195 KB
SIZE OF ALL OBJECTS: 3170 KB
-------------------
END WORK
-------------------
RSS: 153584 KB
HEAP SIZE: 1195 KB
SIZE OF ALL OBJECTS: 149064 KB
-------------------
AFTER FORCED MAJOR GC
-------------------
RSS: 7096 KB
HEAP SIZE: 1195 KB
SIZE OF ALL OBJECTS: 2483 KB
Tenga en cuenta el valor RSS final. Parece que hemos liberado toda la memoria que asignamos para la cadena grande.
No estoy seguro de por qué el segundo ejemplo libera la memoria, pero el primero no, ya que ambos asignan memoria fuera del montón de Ruby. Esta es una reference que podría proporcionar una explicación, pero me interesaría recibir explicaciones de otros.
Liberar la memoria de nuevo en el kernel también tiene un costo. Los asignadores de memoria de espacio de usuario pueden conservar esa memoria (en privado) con la esperanza de que puedan reutilizarse dentro del mismo proceso y no devolverla al kernel para usarla en otros procesos.
@joanbm tiene un muy buen punto aquí. Su article referencia article :
El GC de Ruby libera la memoria gradualmente, por lo que cuando haces GC en 1 gran parte de la memoria apuntada por 1 referencia, se libera todo, pero cuando hay muchas referencias, el GC libera la memoria en pequeños trozos.
Varias llamadas a GC.start
liberarán más y más memoria en el primer ejemplo.
Aquí hay 2 artículos más para profundizar: