简体   繁体   English

NoMemoryError:无法分配内存-Ruby on Rails

[英]NoMemoryError: failed to allocate memory - Ruby on Rails

I generated a simple script that on other occasions has worked for me, but this is because the amount of information in the loop generates a NoMemoryError error. 我生成了一个简单的脚本,该脚本在其他情况下对我有用,但这是因为循环中的信息量会生成NoMemoryError错误。

I have 16 GB of memory and also a lot of virtual memory available. 我有16 GB的内存,也有很多可用的虚拟内存。 When I perform the test, the RAM memory is completely filled. 当我执行测试时,RAM内存已满。

The script is: 脚本是:

  require 'rest-client'
  require 'json'
  require 'open-uri'
  require 'csv'

  def self.qos7705egressdiscard_summary
   xml = File.read("#{Rails.root}/public/Discard_qos7705egress.xml")
   data = RestClient.post("http://10.140.255.1:8080/xmlapi/invoke", xml,{:"Content-Type" => 'application/soap+xml'})
   data_parsed = Hash.from_xml(data)
   return data_parsed
  end

  def self.samqos7705egressdiscardtotal_table
   tabletotal = Hash.new
   data_stats = qos7705egressdiscard_summary['Envelope']['Body']['findResponse']['result']['service.SapEgrQosQueueStatsLogRecord']

   data_stats.map do |qosdiscard_device|
    @devicetotal = qosdiscard_device["monitoredObjectSiteName"]
    @servicetotal = qosdiscard_device["monitoredObjectPointer"]
    @porttotal = qosdiscard_device["displayedName"]
    @queueIdtotal = qosdiscard_device["queueId"]
    @discardinproftotal = qosdiscard_device["droppedInProfOctets"].to_i
    @discardoutproftotal = qosdiscard_device["droppedOutProfOctets"].to_i
    time_unixtotal = (qosdiscard_device["timeCaptured"]).to_i/1000
    @timeCapturedtotal = Time.at(time_unixtotal).strftime("%B %e, %Y at %I:%M %p")
    @discardtotal = @discardinproftotal + @discardoutproftotal
    @device_int_stats_total = (@devicetotal+@porttotal+@queueIdtotal).to_s
     hash = Hash[devicetotal: @devicetotal, servicetotal: @servicetotal, porttotal: @porttotal, queueIdtotal: @queueIdtotal, discardtotal: @discardtotal, device_int_stats_total: @device_int_stats_total, timeCapturedtotal: @timeCapturedtotal, time_unixtotal: time_unixtotal]
     tabletotal << hash
     #tabletotal.write(hash)
   end
  end

The exact error is: 确切的错误是:

NoMemoryError: failed to allocate memory
        from /usr/local/lib/ruby/2.2.0/irb/inspector.rb:108:in `inspect'
        from /usr/local/lib/ruby/2.2.0/irb/inspector.rb:108:in `block in <module:IRB>'
        from /usr/local/lib/ruby/2.2.0/irb/inspector.rb:101:in `call'
        from /usr/local/lib/ruby/2.2.0/irb/inspector.rb:101:in `inspect_value'
        from /usr/local/lib/ruby/2.2.0/irb/context.rb:383:in `inspect_last_value'
        from /usr/local/lib/ruby/2.2.0/irb.rb:661:in `output_value'
        from /usr/local/lib/ruby/2.2.0/irb.rb:490:in `block (2 levels) in eval_input'
        from /usr/local/lib/ruby/2.2.0/irb.rb:623:in `signal_status'
        from /usr/local/lib/ruby/2.2.0/irb.rb:486:in `block in eval_input'
        from /usr/local/lib/ruby/2.2.0/irb/ruby-lex.rb:245:in `block (2 levels) in each_top_level_statement'
        from /usr/local/lib/ruby/2.2.0/irb/ruby-lex.rb:231:in `loop'
        from /usr/local/lib/ruby/2.2.0/irb/ruby-lex.rb:231:in `block in each_top_level_statement'
        from /usr/local/lib/ruby/2.2.0/irb/ruby-lex.rb:230:in `catch'
        from /usr/local/lib/ruby/2.2.0/irb/ruby-lex.rb:230:in `each_top_level_statement'
        from /usr/local/lib/ruby/2.2.0/irb.rb:485:in `eval_input'
        from /usr/local/lib/ruby/2.2.0/irb.rb:395:in `block in start'
        from /usr/local/lib/ruby/2.2.0/irb.rb:394:in `catch'
        from /usr/local/lib/ruby/2.2.0/irb.rb:394:in `start'
        from /usr/local/lib/ruby/gems/2.2.0/gems/railties-4.2.0/lib/rails/commands/console.rb:110:in `start'
        from /usr/local/lib/ruby/gems/2.2.0/gems/railties-4.2.0/lib/rails/commands/console.rb:9:in `start'
        from /usr/local/lib/ruby/gems/2.2.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:68:in `console'
        from /usr/local/lib/ruby/gems/2.2.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
        from /usr/local/lib/ruby/gems/2.2.0/gems/railties-4.2.0/lib/rails/commands.rb:17:in `<top (required)>'
        from bin/rails:4:in `require'
        from bin/rails:4:in `<main>'Maybe IRB bug!

On line 25 I added this tabletotal.write (hash) to be able to write it on disk and not in memory but I got the following error: 在第25行上,我添加了此tabletotal.write (hash)以便能够将其写入磁盘而不是内存中,但是出现以下错误:

NoMethodError: undefined method `write' for {}:Hash

What is the problem here? 这里有什么问题? Also how can I fix it? 另外我该如何解决?

Start by making it less cr*p: 首先减少它的cr * p:

def extract_data(input)
  {
    devicetotal: input["monitoredObjectSiteName"],
    servicetotal: input["monitoredObjectPointer"],
    porttotal: input["displayedName"],
    queueIdtotal: input["queueId"],
    discardinproftotal:  input["droppedInProfOctets"].to_i,
    discardoutproftotal: input["droppedOutProfOctets"].to_i,
    time_unixtotal: input["timeCaptured"].to_i/1000
  }.tap do |h|
    h[:timeCapturedtotal] = Time.at(h[:time_unixtotal]).strftime("%B %e, %Y at %I:%M %p"),
    h[:discardtotal] = h[:discardinproftotal] + h[:discardoutproftotal]
    h[:device_int_stats_total] =(h[:devicetotal]+h[:porttotal]+h[:queueIdtotal]).to_s
  end
end

This method is really easy to test since you just insert input and write assertions about the output. 该方法非常容易测试,因为您只需插入输入并编写有关输出的断言即可。

If you want to map and apply this to the input array you would do: 如果要映射并将其应用于输入数组,则可以执行以下操作:

data_stats.map(&:extract_data)

Your code tries to output a hash but uses the shovel operator like on a array. 您的代码尝试输出哈希,但是像数组一样使用铲操作符。 You need to decide if the appropiate output is an array or a hash. 您需要确定适当的输出是数组还是哈希。

I need all those variables because I use them in a html in table format. 我需要所有这些变量,因为我在表格格式的html中使用它们。

This won't work - the instance variables will only contain the values from the last element as they get overwritten in each iteration. 这将行不通-实例变量将仅包含最后一个元素中的值,因为它们在每次迭代中都会被覆盖。

You instead need to iterate over an array of hashes or objects in the view: 相反,您需要遍历视图中的哈希或对象数组:

<% @stats.each do |s| %>
  <tr>
    <td><%= s[:devicetotal] %></td>
    # ...
  </tr>
<% end %>

If you really want to use instance varibles you need to create a object instance for each element: 如果您确实想使用实例变量,则需要为每个元素创建一个对象实例:

class DataStat
  include ActiveModel::AttributeAssignment
  attr_accessor :devicetotal, :servicetotal # ...

  def self.from_import(input)
    self.new(
      devicetotal: input["monitoredObjectSiteName"],
      servicetotal: input["monitoredObjectPointer"],
      # ...
    )
  end  
end

@stats = data_stats.map { |ds| DataStat.from_import(ds) }

You also need to deal with the issue that you´re running out of memory since you are just slop converting the whole XML document into a Ruby hash. 您还需要处理内存不足的问题,因为您只是将整个XML文档转换为Ruby哈希。 You need to parse it with Nokogiri instead and extract what you actually need. 您需要用Nokogiri解析它,然后提取实际需要的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM