Errno :: ENOMEM问题

时间:2014-05-20 12:12:59

标签: ruby-on-rails ruby child-process spawn

突然在我的staging和prod服务器上(不同但使用相同的VPS提供程序)我在使用我的ruby rails app时收到以下错误:

An Errno::ENOMEM occurred in projects#update:

Cannot allocate memory - identify -format %wx%h '/tmp/Lanscape_originalV220140520-32388-1alg9vz.png[0]'
vendor/bundle/ruby/1.9.1/gems/cocaine-0.3.0/lib/cocaine/command_line/runners/process_runner.rb:17:in `spawn’"

我该如何解决这个问题?

仅供参考我通过重启服务器暂时解决了这个问题

这是导致问题的项目更新文件:

class ProjectUpdatesController < ApplicationController
  before_filter :get_project
  def index
    @project_updates = @project.project_updates
    @project_update = ProjectUpdate.new
  end

  def show
    @project_update = ProjectUpdate.find(params[:id])
  end

  def new
    @project_update = ProjectUpdate.new
  end

  def edit
    @project_update = ProjectUpdate.find(params[:id])
  end

  def create
    @project_update = ProjectUpdate.new(params[:project_update])
    @project_update.project = @project
    return redirect_to :back, :alert => 'abc.' unless current_user.owner?(@project_update.project)
      if @project_update.save
        redirect_to project_project_updates_path(@project), :notice => 'abc.'
      else
        redirect_to project_project_updates_path(@project), :alert => 'abc.'
      end
  end

  def update
    @project_update = ProjectUpdate.find(params[:id])
    return redirect_to :back, :notice => 'you cannot edit project update.' unless current_user.owner?(@project_update.project)
      if @project_update.update_attributes(params[:project_update] )
        redirect_to project_project_updates_path(@project), :notice => 'abc.'
      else
        redirect_to project_project_updates_path(@project), :alert => 'abcy.'
      end
  end

  def destroy
    @project_update = ProjectUpdate.find(params[:id])
    return redirect_to :back, :alert => 'abc.' unless current_user.owner?(@project_update.project)
    @project_update.destroy

    respond_to do |format|
      format.html { redirect_to project_project_updates_url(@project) }
      format.json { head :no_content }
    end
  end

  def get_project
    @project = Project.find(params[:project_id])
  end

  def feed
    @project = Project.find(params[:project_id])
    @project_updates = @project.project_updates
    respond_to do |format|
      format.rss { render :layout => false }
    end
  end
end

1 个答案:

答案 0 :(得分:2)

显然projects#update会以某种方式触发对identify -format ...的系统调用。宝石cocaine用于此目的。它在自述文件中说明如下:

https://github.com/thoughtbot/cocaine#posix-spawn

  

您可以通过安装posix-spawn gem来提高性能。在分叉命令行进程时,此gem可以保持您的应用程序堆不被复制。对于具有大堆的应用,增益可能很大。

我对此进行了测试并重现了错误。

#!/usr/bin/env ruby

require 'posix/spawn'

@arrays = []

def do_echos
        begin
                IO.popen('echo I am a child started with popen') { |io| puts io.read }
        rescue  Errno::ENOMEM => e
                puts "IO.popen: #{e.message}"
        end

        begin
                pid = Process.spawn('echo I am a child started with Process.spawn')
                Process.wait(pid)
        rescue Errno::ENOMEM => e
                puts "Process.spawn: #{e.message}"
        end

        child = POSIX::Spawn::Child.new('echo', 'I am a child started with posix_spawn');
        puts child.out
end

def fill_mem
        begin
                while true
                        @arrays << Array.new(10000000)
                end
        rescue NoMemoryError
                puts "Allocated arrays until out of memory..."
        end
end

do_echos
fill_mem
do_echos

输出:

  

我是一个从popen开始的孩子   我是一个从Process.spawn开始的孩子   我是一个刚开始使用posix_spawn的孩子   分配的数组直到内存不足...
  IO.popen:无法分配内存 - echo
  Process.spawn:无法分配内存 - echo
  我是一个以posix_spawn

开始的孩子

总之,我建议您遵循可卡因的建议。

  

要包含posix-spawn,只需将其添加到Gemfile中,或者,如果您不使用bundler,请安装gem。

https://github.com/rtomayko/posix-spawn