4

In my project there is one script that returns the list of products which I have to display in a table.

To store the input of the script I used IO.popen:

@device_list = []
IO.popen("device list").each do |device|
  @device_list << device
end

device list is the command that will give me the product list.

I return the @device_list array to my view for displaying by iterating it.

When I run it I got an error:

Errno::ENOMEM (Cannot allocate memory):
for IO.popen

I have on another script device status that returns only true and false but I got the same error:

def check_status(device_id)        
    @stat = system("status device_id")
    if @stat == true
         "sold"
    else
         "not sold"
    end
  end

What should I do?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
user2622247
  • 1,059
  • 2
  • 15
  • 26
  • Whenever I see Rails running shell commands I wonder about permissions. Are you sure the user Rails is running as has permission to run the script? Can you run it from `rails console`? Can you run other shell commands from your app (e.g. `ls`)? I realize the error is pointing you to memory, but perhaps it's just getting confused here. – jb_314 Dec 08 '13 at 08:13
  • Is your machine starved for memory? – SLD Dec 08 '13 at 21:41
  • @np_ When I run these commands from my `rails console` they are running fine. – user2622247 Dec 09 '13 at 07:50

2 Answers2

15

Both IO.popen and Kernel#system can be expensive operations in terms of memory because they both rely on fork(2). Fork(2) is a Unix system call which creates a child process that clones the parent's memory and resources. That means, if your parent process uses 500mb of memory, then your child would also use 500mb of memory. Each time you do Kernel#system or IO.popen you increase your application's memory usage by the amount of memory it takes to run your Rails app.

If your development machine has more RAM than your production server or if your production server produces a lot more output, there are two things you could do:

  1. Increase memory for your production server.
  2. Do some memory management using something like Resque.

You can use Resque to queue those operations as jobs. Resque will then spawn "workers"/child processes to get a job from the queue, work on it and then exit. Resque still forks, but the important thing is that the worker exits after working on the task so that frees up memory. There'll be a spike in memory every time a worker does a job, but it will go back to the baseline memory of your app every after it.

You might have to do both options above and look for other ways to minimize the memory-usage of your app.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Gjaldon
  • 5,534
  • 24
  • 32
0

It seems your output from device list is too large.

"Cannot allocate memory (Errno::ENOMEM)" is a useful link which describes the question.

Limit the output of device list and check. Then you can know if it is a memory issue or not.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Maleen Abewardana
  • 13,600
  • 4
  • 36
  • 39
  • Ok I already looked into that thread. but i have on another script command as `device status` that returns only **true** and **false** but i got the same error. – user2622247 Dec 04 '13 at 11:26