我正在开发Ruby on Rails应用程序。我是Ruby / Rails的新手。我使用Ruby 2.2.0和Rails 4.2。当我运行类似的命令时:
rails g migration SomeMigrationName
它失败了
Cannot allocate memory - fork(2) (Errno::ENOMEM)
我将Macbook Pro与OS X 10.10一起安装在主板上,并使用Vagrant / Virtualbox来运行用于Rails开发的虚拟机(Ubuntu 14.04)。
这是我的Vagrant文件:
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
我已经读到,当RAM超出限制时会发生这样的错误,但是我对另一个运行多个Python / Tornado应用程序,MongoDB和Redis的开发环境使用相同的配置(流浪文件),并且一切正常。
我是否需要增加vb.memory的值,或者这是一个Ruby错误?
当Ruby调用时fork
,即使只将fork调用到exec
另一个小进程(如),OS也会复制整个父进程的地址空间ls
。暂时,您的系统需要能够分配至少一块Ruby父进程大小的内存,然后再将其分解为子进程的实际需求。
因此,Rails通常非常消耗内存。然后,如果使用fork
,则需要两倍的内存。
TL; DR如果可以控制代码,请使用posix-spawn而不是fork。否则,给您的VM 1024MB或一点额外的交换空间,以占用fork
通话的余量
Ruby内存使用示例fork
随机抽取一个虚拟机,该虚拟机已禁用交换空间:
$ free -m
total used free shared buffers cached
Mem: 1009 571 438 0 1 35
-/+ buffers/cache: 534 475
Swap: 0 0 0
查看Mem:
行和free
列。这大约是您对新流程的大小限制,在我的情况下为438
MiB
我buffers/cached
已经为此测试被刷新,以至于我的free
记忆力已达到极限。如果buffers/cache
值较大,则可能需要考虑这些值。当进程需要内存时,Linux可以清除过时的缓存。
耗尽一些内存
创建一个红宝石进程,并使用一个与可用内存大小相近的字符串。该ruby
过程有一些开销,因此不会完全匹配free
。
$ ruby -e 'mb = 380; a="z"*mb*2**20; puts "=)"'
=)
然后将字符串稍大一些:
$ ruby -e 'mb = 385; a="z"*mb*2**20; puts "=)"'
-e:1:in `*': failed to allocate memory (NoMemoryError)
from -e:1:in `<main>'
fork
在红宝石过程中添加一个,mb
直到运行为止。
$ ruby -e 'mb = 195; a="z"*mb*2**20; fork; puts "=)"'
=)
稍大的fork过程将产生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>'
运行带有反引号的命令会以fork
so启动该过程,其结果相同:
$ ruby -e 'mb = 200; a="z"*mb*2**20; `ls`'
-e:1:in ``': Cannot allocate memory - ls (Errno::ENOMEM)
from -e:1:in `<main>'
因此,您需要大约两倍于系统上可用的父进程内存来派生新进程。MRI Rubyfork
的多进程模型非常依赖,这是因为Ruby的设计使用了全局解释器锁(GIL),该全局解释器锁在每个ruby进程中一次只能执行一个线程。
我相信Python在fork
内部使用的很少。当您os.fork
在Python中使用时,会发生以下情况:
python -c 'a="c"*420*2**20;'
python -c 'import os; a="c"*200*2**20; os.fork()'
Oracle关于此问题有详细的文章,并讨论了使用.NET的替代方法posix_spawn()
。本文针对Solaris,但这是POSIX Unix的一般性问题,因此适用于Linux(如果不是大多数Unices)。
posix-spawn
如果您可以控制代码,也可以使用Ruby实现。该模块不会替换Rails中的任何内容,因此除非您替换了对fork
自己的调用,否则它对您没有帮助。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句