簡體   English   中英

NoMemoryError:無法分配內存-Ruby on Rails

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

我生成了一個簡單的腳本,該腳本在其他情況下對我有用,但這是因為循環中的信息量會生成NoMemoryError錯誤。

我有16 GB的內存,也有很多可用的虛擬內存。 當我執行測試時,RAM內存已滿。

腳本是:

  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

確切的錯誤是:

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!

在第25行上,我添加了此tabletotal.write (hash)以便能夠將其寫入磁盤而不是內存中,但是出現以下錯誤:

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

這里有什么問題? 另外我該如何解決?

首先減少它的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

該方法非常容易測試,因為您只需插入輸入並編寫有關輸出的斷言即可。

如果要映射並將其應用於輸入數組,則可以執行以下操作:

data_stats.map(&:extract_data)

您的代碼嘗試輸出哈希,但是像數組一樣使用鏟操作符。 您需要確定適當的輸出是數組還是哈希。

我需要所有這些變量,因為我在表格格式的html中使用它們。

這將行不通-實例變量將僅包含最后一個元素中的值,因為它們在每次迭代中都會被覆蓋。

相反,您需要遍歷視圖中的哈希或對象數組:

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

如果您確實想使用實例變量,則需要為每個元素創建一個對象實例:

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) }

您還需要處理內存不足的問題,因為您只是將整個XML文檔轉換為Ruby哈希。 您需要用Nokogiri解析它,然后提取實際需要的東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM