Próbuję zrozumieć, kiedy pamięć przydzielona poza stertą Rubin zostaje zwrócona do systemu operacyjnego. Rozumiem, że Ruby nigdy nie zwraca pamięci przydzielonej do jego sterty, ale nadal nie jestem pewien co do zachowania pamięci sterty. tj. te obiekty, które nie mieszczą się w 40-bajtowej RAWALNOŚCI.Dlaczego ten program Ruby nie zwraca pamięci sterty do systemu operacyjnego?
Rozważmy następujący program, który przydziela niektóre duże ciągi, a następnie wymusza większy GC.
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')
Uruchamiając ten program za pomocą Rubiego 2.2.3 na MRI, generuje następujący wynik. Po wymuszonym głównym GC wielkość sterty jest zgodna z oczekiwaniami, ale RSS nie zmniejszył się znacząco.
-------------------
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
Porównaj te wyniki z następującymi wynikami, gdy przydzielimy jeden duży obiekt zamiast wielu mniejszych obiektów.
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
Uwaga na ostatnią wartość RSS. Wydaje się, że uwolniliśmy całą pamięć, którą przydzieliliśmy na duży ciąg.
Nie jestem pewien, dlaczego drugi przykład zwalnia pamięć, ale pierwszy przykład nie jest taki, ponieważ oba przydzielają pamięć do stosu Ruby. To jest jeden numer reference, który może dostarczyć wyjaśnienia, ale byłbym zainteresowany wyjaśnieniami od innych.
Zwolnienie pamięci z powrotem do jądra również kosztuje. Pamięć przestrzeni użytkownika Przydzielacze mogą przechowywać tę pamięć (prywatnie) w nadziei, że będzie ona mogła zostać ponownie użyta w tym samym procesie i nie zostanie zwrócona do jądra, aby można ją było wykorzystać w innych procesach.
Zapisywanie do tego wątku. Jestem * bardzo * zainteresowany również tym. – dimitarvp
Podstawowa różnica jest w pierwszym przykładzie, gdzie powstają 600k * nowe * obiekty, w drugim tylko jeden. Chociaż całkowity rozmiar danych * referencyjnych * jest taki sam, pierwszy przykład wymaga 600 tysięcy razy więcej slotów dla obiektów referencyjnych (które prawdopodobnie nigdy lub później nie zostaną zregenerowane do systemu operacyjnego). – joanbm
Proponuję zapoznać się z [artykułem] (http://www.sitepoint.com/ruby-uses-memory/) i powiązać [wyjaśnienie] (http://rocket-science.ru/hacking/2013/12/17/ruby-memory-pułapek /) z 'RVALUE's. Nie jestem pewien, czy są one poprawne, tylko Koichi znany jako ko1 może wiedzieć. Lub jakiś silnie zdeterminowany entuzjasta, analizujący źródła Rubiego. – joanbm