2015-02-02 23 views
10

Jestem w trakcie opracowywania aplikacji Ruby on Rails. Jestem nowicjuszem w Ruby/Rails. Używam Ruby 2.2.0 i Rails 4.2. Kiedy uruchomić poleceniem:Ruby: Nie można przydzielić pamięci

rails g migration SomeMigrationName 

zawiedzie z

Cannot allocate memory - fork(2) (Errno::ENOMEM) 

używam MacBook Pro mid 2014 z OS X 10.10 na pokładzie oraz Vagrant/Virtualbox uruchomić maszynę wirtualną (Ubuntu 14.04) do rozwoju Railsów.

Oto moja Vagrant file:

Vagrant.configure(2) do |config| 
    config.vm.box = "ubuntu/trusty64" 
    config.vm.network "forwarded_port", guest: 3000, host: 3000 
    config.vm.synced_folder "dev", "/home/vagrant/dev" 
    config.vm.synced_folder "opt", "/opt" 
    config.vm.provider "virtualbox" do |vb| 
    vb.memory = "512" 
    end 
end 

Czytałem, że taki błąd występuje, gdy RAM jest poza limitem, ale używam tego samego pliku config (Vagrant) na innym środowisku dev, który prowadzi kilka Aplikacje Python/Tornado, MongoDB i Redis i wszystko działa dobrze.

Czy muszę zwiększyć wartość vb.memory lub jest to błąd Ruby?

+0

Trudno powiedzieć, czy potrzebujesz więcej pamięci RAM. Ogólnie rzecz biorąc, średnia aplikacja szyn może korzystać z 512M. Railsy ładują całą aplikację do pamięci x jakkolwiek wiele serwerów/procesów, które masz zamiar. Zwykle ustawiam pamięć RAM na 2 GB, aby nawet próbować. Robię moje dev na moim Macu, chociaż ogólnie, nie Virtual Box. –

Odpowiedz

23

Kiedy Ruby zadzwoni pod numer fork, system operacyjny wykona kopię całej nadrzędnej przestrzeni adresowej procesów, nawet jeśli widełki będą wywoływane tylko pod exec inny mały proces, taki jak ls. Chwile, twój system musi mieć możliwość przydzielenia kawałka pamięci co najmniej o rozmiar przedinty rodzica Rubiego, zanim zwinnie go do tego, czego proces potomny potrzebuje.

Tak więc szyny są generalnie dość głodne pamięci. Następnie, jeśli coś używa fork, potrzebujesz dwa razy więcej pamięci.

TL; DR Użyj posix-spawn zamiast widelca, jeśli masz kontrolę nad kodem. W przeciwnym razie dać VM 1024MB lub trochę więcej przestrzeni wymiany, aby wypełnić powstałą lukę na fork rozmowy

Usage


Przykład Ruby Memory z fork

Take losową VM, ten ma przestrzeń wymiany niepełnosprawnych:

$ free -m 
      total  used  free  shared buffers  cached 
Mem:   1009  571  438   0   1   35 
-/+ buffers/cache:  534  475 
Swap:   0   0   0 

spojrzenie na Mem:free rzędu i kolumn. Jest to o około limit rozmiaru dla nowego procesu, w moim przypadku 438 MiB

My buffers/cached zostały już flushed dla tego testu tak, że moja pamięć free jest to ograniczenie. Może być konieczne uwzględnienie wartości buffers/cache, jeśli są one duże. Linux ma możliwość eksmisji nieaktualnych pamięci podręcznych, gdy pamięć jest potrzebna w procesie.


zużyć trochę pamięci

Utwórz proces rubinowy sznurkiem wokół wielkości wolnej pamięci. Jest pewien narzut dla procesu ruby, więc nie będzie dokładnie pasował do free.

$ ruby -e 'mb = 380; a="z"*mb*2**20; puts "=)"' 
=) 


Następnie zrób ciąg nieco większy:

$ ruby -e 'mb = 385; a="z"*mb*2**20; puts "=)"' 
-e:1:in `*': failed to allocate memory (NoMemoryError) 
     from -e:1:in `<main>' 


Dodaj fork do procesu ruby, zmniejszając mb aż skończy.

$ ruby -e 'mb = 195; a="z"*mb*2**20; fork; puts "=)"' 
=) 


Nieco większy proces widelec będzie produkować błąd ENOMEM:

$ ruby -e 'mb = 200; a="z"*mb*2**20; fork; puts "=)"' 
-e:1:in `fork': Cannot allocate memory - fork(2) (Errno::ENOMEM) 
     from -e:1:in `<main>' 


Uruchomienie polecenia z backticks uruchamia ten proces z fork więc ten sam wynik:

$ ruby -e 'mb = 200; a="z"*mb*2**20; `ls`' 
-e:1:in ``': Cannot allocate memory - ls (Errno::ENOMEM) 
     from -e:1:in `<main>' 


Tak więc, potrzebujesz około dwa razy więcej niż pamięć nadrzędna w stanie w systemie rozwidlić nowy proces. MRI Ruby opiera się w dużej mierze na fork, ponieważ jest to model wieloprocesowy, jest to spowodowane projektem Ruby, który używa global interpreter lock (GIL), który pozwala tylko na wykonanie jednego wątku w czasie na proces ruby.

Wierzę, że Python ma wewnętrznie mniejszą przydatność do używania fork. Kiedy używasz os.fork w Pythonie, to samo dzieje się jednak:

python -c 'a="c"*420*2**20;' 
python -c 'import os; a="c"*200*2**20; os.fork()' 


Oracle mają detailed article on the problem i rozmawiać na temat korzystania z alternatywy posix_spawn(). Artykuł jest skierowany do Solaris, ale jest to ogólny problem z Uniksem w systemie POSIX, dotyczy to więc Linuksa (jeśli nie większości Uniksów).

Istnieje również implementacja języka Ruby w wersji posix-spawn, której można użyć, jeśli masz kontrolę nad kodem. Ten moduł nie zastępuje niczego w Railsach, więc nie pomoże ci tutaj, chyba że sam zmienisz połączenia na fork.

+0

Pewnego dnia nagle mieliśmy podobny problem 'Errno :: ENOMEM: Nie można przydzielić pamięci - plik -b --mime/tmp/blabla.jpg', a to dlatego, że wprowadziliśmy dodatkowy proces monitorowania (agent DataDog, który pochłonął 600MB) ... w każdym razie '+ 1' na czek' free -m' :) – equivalent8

+0

Wow, to absurdalnie duże dla agenta monitorującego. – Matt

Powiązane problemy