Ruby on rails 经过一个过程后,为什么Ruby中的内存会一直保持不变?

Ruby on rails 经过一个过程后,为什么Ruby中的内存会一直保持不变?,ruby-on-rails,ruby,memory,memory-management,memory-leaks,Ruby On Rails,Ruby,Memory,Memory Management,Memory Leaks,我将Rails4与Ruby 2.1.0结合使用。我有一个代码,它需要大约2GB的内存来完成这个过程,但问题是在完成这个过程之后…为什么内存使用率仍然在上升 我还将nil赋值给使用后的变量,该变量节省了300 MB,但Ruby进程仍使用了大量内存 下面是重现问题的示例代码: def download_data(params, options = {}) $file_name = '' portfolio_names = Portfolio.get_names buildin

我将Rails4与Ruby 2.1.0结合使用。我有一个代码,它需要大约2GB的内存来完成这个过程,但问题是在完成这个过程之后…为什么内存使用率仍然在上升

我还将
nil
赋值给使用后的变量,该变量节省了300 MB,但Ruby进程仍使用了大量内存

下面是重现问题的示例代码:

def download_data(params, options = {})
    $file_name = ''
    portfolio_names = Portfolio.get_names
    building_names = Building.get_names
    tenant_names = Tenant.get_names
    meter_names = Meter.get_meter_names

    @portfolio_info, @building_info, @tenant_info, @meter_id, @from_date, @to_date = params[:portfolio_name], params[:building_name], params[:tenant_name], params[:meter_id], params[:from_date], params[:to_date]

    @from_date = DateTime.parse(@from_date).to_i
    @to_date = DateTime.parse(@to_date).to_i

    @building_f_name = building_names["#{@building_info}"]
    unless params[:fields].nil?
      @fields = params[:fields].split('_')
      @columns = []
      @fields.each do |f|
        if f.length > 0
          @columns << MeterData.new.show_real_value_of_meter_data_field_revert(f).to_sym
        end
      end
      @columns << 'date_time'.to_sym
      @columns << 'tenant'.to_sym
      @columns << 'meter_id'.to_sym
    else
      @columns = [:id, :date_time, :w3pht, :whintvlrec, :w__3phmaxavgdmd, :tenant, :meter_id]
    end


    #### database fetch ###########
    @meter_data = MeterData.find_by_sql("SELECT tenant, meter_id, SUM(van) as van, SUM(vbn) as vbn,
                                           SUM(vcn) as vcn, SUM(ia) as ia, SUM(ib) as ib, SUM(ic) as ic,
                                           SUM(w3pht) as w3pht, SUM(pf3pht) as pf3pht, SUM(f) as f,
                                           SUM(whrec) as whrec, SUM(whtot) as whtot, SUM(varhrec) as varhrec,
                                           SUM(varhtot) as varhtot, SUM(whintvlrec) as whintvlrec,
                                           SUM(whintvldel) as whintvldel, SUM(w__phavg) as w__phavg,
                                           SUM(var__3phavg) as var__3phavg, SUM(w_3phavg) as w_3phavg,
                                           SUM(var_3phavg) as var_3phavg, SUM(phai) as phai, SUM(phbi) as phbi,
                                           SUM(phci) as phci, SUM(w__3phmaxavgdmd) as w__3phmaxavgdmd,
                                           MAX(w__3phmaxavgdmd) as w__3phmaxavgdmd_max, SUM(var__3phmaxavgdmd) as var__3phmaxavgdmd,
                                           SUM(w_3phmaxavgdmd) as w_3phmaxavgdmd, SUM(var_3phmaxavgdmd) as var_3phmaxavgdmd,
                                           date_time FROM `meter_data` WHERE (`date_time_i` >= #{@from_date} AND `date_time_i` <= #{@to_date}
                                           AND building = '#{@building_info}') GROUP by tenant, meter_id, date_time
                                           ORDER BY `meter_data`.`date_time_i` ASC")
    sleep 0.5
    @meter_sum = MeterData.find_by_sql("SELECT meter_id, SUM(van) as van, SUM(vbn) as vbn, SUM(vcn) as vcn,
                                                    SUM(ia) as ia, SUM(ib) as ib, SUM(ic) as ic, SUM(w3pht) as w3pht,
                                                    SUM(pf3pht) as pf3pht, SUM(f) as f, SUM(whrec) as whrec,
                                                    SUM(whtot) as whtot, SUM(varhrec) as varhrec, SUM(varhtot) as varhtot,
                                                    SUM(whintvlrec) as whintvlrec, SUM(whintvldel) as whintvldel,
                                                    SUM(w__phavg) as w__phavg, SUM(var__3phavg) as var__3phavg,
                                                    SUM(w_3phavg) as w_3phavg, SUM(var_3phavg) as var_3phavg,
                                                    SUM(phai) as phai, SUM(phbi) as phbi, SUM(phci) as phci,
                                                    SUM(w__3phmaxavgdmd) as w__3phmaxavgdmd, MAX(w__3phmaxavgdmd) as w__3phmaxavgdmd_max,
                                                    SUM(var__3phmaxavgdmd) as var__3phmaxavgdmd, SUM(w_3phmaxavgdmd) as w_3phmaxavgdmd,
                                                    SUM(var_3phmaxavgdmd) as var_3phmaxavgdmd, date_time FROM `meter_data`
                                                    WHERE (`date_time_i` >= #{@from_date} AND `date_time_i` <= #{@to_date} AND building = '#{@building_info}')
                                                    GROUP by meter_id ORDER BY `meter_data`.`date_time_i` ASC")
    @meter_data_max = MeterData.find_by_sql("SELECT tenant, meter_id, MAX(w__3phmaxavgdmd) as w__3phmaxavgdmd,
                                               date_time FROM `meter_data` WHERE (`date_time_i` >= #{@from_date} AND `date_time_i` <= #{@to_date}
                                               AND building = '#{@building_info}') GROUP by tenant, meter_id
                                               ORDER BY `meter_data`.`date_time_i` ASC")
    sleep 0.5
    @uniq_meter_id = MeterData.select(:meter_id).where("`date_time_i` >= #{@from_date} AND `date_time_i` <= #{@to_date} AND building = '#{@building_info}'").uniq(:meter_id)
    #### database fetch ###########

    p = Axlsx::Package.new
    wb = p.workbook
    wb.styles do |s|

      styles_hash  = AxlsxStylesHash.get s

      wb.add_worksheet(:name => "Building data details") do |sheet|
        $row_num = 0
        meter_extra = MeterExtra.new

        columns_ = []; @columns.each { |s| columns_ << "#{s}_".to_s }

        sheet.add_row []
        $row_num += 1
        sheet.add_row ["Building report of #{@building_f_name}   #{@from_date} to #{@to_date}"], :style => styles_hash[:heading_cell]
        $row_num += 1
        sheet.add_row []
        $row_num += 1
        sheet.add_row []
        $row_num += 1

        sheet.merge_cells("A2:Q2")

        new_columns_ = []
        new_columns_ <<  "Date & Time" if columns_.include?('date_time_')
        new_columns_ <<  "Building" if columns_.include?('building_')
        new_columns_ <<  "Tenant" if columns_.include?('tenant_')
        new_columns_ <<  "Meter ID" if columns_.include?('meter_id_')
        new_columns_ <<  "Meter Name" if columns_.include?('meter_id_')
        new_columns_ <<  "van" if columns_.include?('van_')
        new_columns_ <<  "vbn" if columns_.include?('vbn_')
        new_columns_ <<  "vcn" if columns_.include?('vcn_')
        new_columns_ <<  "ia" if columns_.include?('ia_')
        new_columns_ <<  "ib" if columns_.include?('ib_')
        new_columns_ <<  "ic" if columns_.include?('ic_')
        new_columns_ <<  "w3pht" if columns_.include?('w3pht_')
        new_columns_ <<  "pf3pht" if columns_.include?('pf3pht_')
        new_columns_ <<  "f" if columns_.include?('f_')
        new_columns_ <<  "whrec" if columns_.include?('whrec_')
        new_columns_ <<  "whtot" if columns_.include?('whtot_')
        new_columns_ <<  "varhrec" if columns_.include?('varhrec_')
        new_columns_ <<  "varhtot" if columns_.include?('varhtot_')
        new_columns_ <<  "whintvlrec" if columns_.include?('whintvlrec_')
        new_columns_ <<  "whintvldel" if columns_.include?('whintvldel_')
        new_columns_ <<  "w+phavg" if columns_.include?('w__phavg_')
        new_columns_ <<  "var+3phavg" if columns_.include?('var__3phavg_')
        new_columns_ <<  "w-3phavg" if columns_.include?('w_3phavg_')
        new_columns_ <<  "var-3phavg" if columns_.include?('var_3phavg_')
        new_columns_ <<  "phai" if columns_.include?('phai_')
        new_columns_ <<  "phbi" if columns_.include?('phbi_')
        new_columns_ <<  "phci" if columns_.include?('phci_')
        new_columns_ <<  "w+3phmaxavgdmd" if columns_.include?('w__3phmaxavgdmd_')
        new_columns_ <<  "var+3phmaxavgdmd" if columns_.include?('var__3phmaxavgdmd_')
        new_columns_ <<  "w-3phmaxavgdmd" if columns_.include?('w_3phmaxavgdmd_')
        new_columns_ <<  "var-3phmaxavgdmd" if columns_.include?('var_3phmaxavgdmd_')

        sheet.add_row new_columns_, :style => styles_hash[:green_bold_border_cell]
        $row_num += 1
        t = 1; @meter_data.each do |m|
          new_columns_data = []
          if columns_.include?('date_time_')
            m_date_time = m['date_time']
            new_columns_data << ( m_date_time.nil? ? '--' : m_date_time)
          end
          if columns_.include?('building_')
            m_building = m_building
            new_columns_data << ( m_building.nil? ? '--' : building_names["#{m_building}"])
          end
          if columns_.include?('tenant_')
            m_tenant = m['tenant']
            new_columns_data << ( m_tenant.nil? ? '--' : tenant_names["#{m_tenant}"])
          end
          if columns_.include?('meter_id_')
            m_meter_id = m['meter_id']
            new_columns_data << ( m_meter_id.nil? ? '--' : m_meter_id)
          end
          if columns_.include?('meter_id_')
            m_meter_id = m['meter_id']
            new_columns_data << ( meter_extra.get_meter_name(m_meter_id.nil? ? '--' : m_meter_id) )
          end
          if columns_.include?('van_')
            m_van = m.van
            new_columns_data << ( m_van.nil? ? '--' : m_van )
          end
          if columns_.include?('vbn_')
            m_vbn = m.vbn
            new_columns_data << ( m_vbn.nil? ? '--' : m_vbn )
          end
          if columns_.include?('vcn_')
            m_vcn = m.vcn
            new_columns_data << ( m_vcn.nil? ? '--' : m_vcn )
          end
          if columns_.include?('ia_')
            m_ia = m.ia
            new_columns_data << ( m_ia.nil? ? '--' : m_ia )
          end
          if columns_.include?('ib_')
            m_ib = m.ib
            new_columns_data << ( m_ib.nil? ? '--' : m_ib )
          end
          if columns_.include?('ic_')
            m_ic = m.ic
            new_columns_data << ( m_ic.nil? ? '--' : m_ic )
          end
          if columns_.include?('w3pht_')
            m_w3pht = m.w3pht
            new_columns_data << ( m_w3pht.nil? ? '--' : m_w3pht )
          end
          if columns_.include?('pf3pht_')
            m_pf3pht = m.pf3pht
            new_columns_data << ( m_pf3pht.nil? ? '--' : m_pf3pht )
          end
          if columns_.include?('f_')
            m_f = m.f
            new_columns_data << ( m_f.nil? ? '--' : m_f )
          end
          if columns_.include?('whrec_')
            m_whrec = m.whrec
            new_columns_data << ( m_whrec.nil? ? '--' : m_whrec )
          end
          if columns_.include?('whtot_')
            m_whtot = m.whtot
            new_columns_data << ( m_whtot.nil? ? '--' : m_whtot )
          end
          if columns_.include?('varhrec_')
            m_varhrec = m.varhrec
            new_columns_data << ( m_varhrec.nil? ? '--' : m_varhrec )
          end
          if columns_.include?('varhtot_')
            m_varhtot = m.varhtot
            new_columns_data << ( m_varhtot.nil? ? '--' : m_varhtot )
          end
          if columns_.include?('whintvlrec_')
            m_whintvlrec = m.whintvlrec
            new_columns_data << ( m_whintvlrec.nil? ? '--' : m_whintvlrec )
          end
          if columns_.include?('whintvldel_')
            m_whintvldel = m.whintvldel
            new_columns_data << ( m_whintvldel.nil? ? '--' : m_whintvldel )
          end
          if columns_.include?('w__phavg_')
            m_w__phavg = m.w__phavg
            new_columns_data << ( m_w__phavg.nil? ? '--' : m_w__phavg )
          end
          if columns_.include?('var__3phavg_')
            m_var__3phavg = m.var__3phavg
            new_columns_data << ( m_var__3phavg.nil? ? '--' : m_var__3phavg )
          end
          if columns_.include?('w_3phavg_')
            m_w_3phavg = m.w_3phavg
            new_columns_data << ( m_w_3phavg.nil? ? '--' : m_w_3phavg )
          end
          if columns_.include?('var_3phavg_')
            m_var_3phavg = m.var_3phavg
            new_columns_data << ( m_var_3phavg.nil? ? '--' : m_var_3phavg )
          end
          if columns_.include?('phai_')
            m_phai = m.phai
            new_columns_data << ( m_phai.nil? ? '--' : m_phai )
          end
          if columns_.include?('phbi_')
            m_phbi = m.phbi
            new_columns_data << ( m_phbi.nil? ? '--' : m_phbi )
          end
          if columns_.include?('phci_')
            m_phci = m.phci
            new_columns_data << ( m_phci.nil? ? '--' : m_phci )
          end
          if columns_.include?('w__3phmaxavgdmd_')
            m_w__3phmaxavgdmd = m.w__3phmaxavgdmd
            new_columns_data << ( m_w__3phmaxavgdmd.nil? ? '--' : m_w__3phmaxavgdmd )
          end
          if columns_.include?('var__3phmaxavgdmd_')
            m_var__3phmaxavgdmd = m.var__3phmaxavgdmd
            new_columns_data << ( m_var__3phmaxavgdmd.nil? ? '--' : m_var__3phmaxavgdmd )
          end
          if columns_.include?('w_3phmaxavgdmd_')
            m_w_3phmaxavgdmd = m.w_3phmaxavgdmd
            new_columns_data << (m_w_3phmaxavgdmd.nil? ? '--' : m_w_3phmaxavgdmd )
          end
          if columns_.include?('var_3phmaxavgdmd_')
            m_var_3phmaxavgdmd = m.var_3phmaxavgdmd
            new_columns_data << ( m_var_3phmaxavgdmd.nil? ? '--' : m_var_3phmaxavgdmd )
          end

          if t == 1
            sheet.add_row new_columns_data , :style => styles_hash[:simple_green_cell], :widths=>[20]
          else
            sheet.add_row new_columns_data, :style => styles_hash[:simple_white_cell], :widths=>[20]
          end
          $row_num += 1
          t = 0 if t == 2
          t += 1
          puts $row_num
          m = nil
        end
        @meter_data = nil
        ## logo ##
        ReportBillLogo.put sheet, $row_num
        sheet = nil;
      end


      ## summary calculation ##
      wb.add_worksheet(:name => "Summary") do |sheet|
        $row_num = 0
        sheet.add_row []
        $row_num += 1
        sheet.add_row ["Summary report of #{@building_f_name}   #{@from_date} to #{@to_date}"], :style => styles_hash[:heading_cell]
        $row_num += 1
        sheet.add_row []
        $row_num += 1
        sheet.add_row []
        $row_num += 1
        sheet.merge_cells("A1:Q1")

        columns_ = []; @columns.each { |s| columns_ << "#{s}_".to_s }

        new_columns_ = []
        new_columns_ <<  "Meter ID"
        new_columns_ <<  "Meter Name"
        new_columns_ <<  "Max KW"

        sheet.add_row new_columns_, :style => styles_hash[:green_bold_border_cell]
        $row_num += 1

        t = 0
        @meter_data_max.each do |m|
          new_columns_data = []
          new_columns_data << m.meter_id
          new_columns_data << meter_names["#{m.meter_id}"]
          new_columns_data << ( m.w__3phmaxavgdmd.nil? ? '' : m.w__3phmaxavgdmd )

          if t == 1
            sheet.add_row new_columns_data, :style => styles_hash[:simple_green_cell], :widths=>[25]
          else
            sheet.add_row new_columns_data, :style => styles_hash[:simple_white_cell], :widths=>[25]
          end
          $row_num += 1
          t = 0 if t == 2
          t += 1
          m = nil;
        end
        ## logo ##
        ReportBillLogo.put sheet, $row_num
        sheet = nil
      end

      ## summary calculation ##

      ## summary calculation ##
      wb.add_worksheet(:name => "Energy consumed") do |sheet|
        $row_num = 0
        sheet.add_row []
        $row_num += 1
        sheet.add_row ["Energy consumed report of #{@building_f_name}   #{@from_date} to #{@to_date}"], :style => styles_hash[:heading_cell]
        $row_num += 1
        sheet.add_row []
        $row_num += 1
        sheet.add_row []
        $row_num += 1
        sheet.merge_cells("A2:Q2")

        engery = []
        @uniq_meter_id.each do |f|
          start = MeterData.find_by_sql("select whtot from meter_data where `date_time_i` >= #{@from_date} AND meter_id = '#{f.meter_id}' ORDER BY date_time_i ASC limit 1")
          eand  = MeterData.find_by_sql("select whtot from meter_data where `date_time_i` <= #{@from_date} AND meter_id = '#{f.meter_id}' ORDER BY date_time_i DESC limit 1")
          sleep 0.009
          begin
            engery << (eand.last.whtot.to_i - start.first.whtot.to_i)
          rescue
            engery << '--'
          end
          start = nil; eand = nil;
          f = nil;
        end
        columns_ = []; @columns.each { |s| columns_ << "#{s}_".to_s }
        new_columns_ = []
        new_columns_ <<  "Meter ID"
        new_columns_ <<  "Meter Name"
        new_columns_ <<  "Subtraction result"
        new_columns_ <<  "Aggregate result"
        sheet.add_row new_columns_, :style => styles_hash[:green_bold_border_cell]
        $row_num += 1
        flage = 0
        t = 0
        @meter_sum.each do |m|
          new_columns_data = []
          new_columns_data << m.meter_id
          new_columns_data << meter_names["#{m.meter_id}"]
          new_columns_data << engery[flage]
          new_columns_data << m.whintvlrec
          if t == 1
            sheet.add_row new_columns_data, :style => styles_hash[:simple_green_cell], :widths=>[25]
          else
            sheet.add_row new_columns_data, :style => styles_hash[:simple_white_cell], :widths=>[25]
          end
          $row_num += 1
          flage += 1
          t = 0 if t == 2
          t += 1
          m = nil
        end

        ## logo ##
        ReportBillLogo.put sheet, $row_num
        sheet = nil;
      end
    end

    $file_name = "tmp/#{@building_info} . #{@from_date} - #{@to_date} _ #{Time.new.to_i}.xlsx"
    p.serialize($file_name)
    p = nil; wb = nil;
    @meter_data = nil; @meter_data_max = nil; @meter_sum = nil;
    return $file_name
  end
# total records = 5, 00, 000 
def下载_数据(参数,选项={})
$file_name=“”
portfolio\u name=portfolio.get\u name
building\u names=building.get\u names
租户名称=租户。获取租户名称
meter\u names=meter.get\u meter\u names
@公文包信息、@building\u info、@tenant\u info、@meter\u id、@from\u date、@to\u date=params[:公文包名称]、params[:building\u name]、params[:tenant\u name]、params[:meter\u id]、params[:from\u date]、params[:to\u date]
@from_date=DateTime.parse(@from_date).to_i
@to_date=DateTime.parse(@to_date).to_i
@建筑物名称=建筑物名称[“{@building\u info}]
除非参数[:字段].nil?
@字段=参数[:字段]。拆分(“”)
@列=[]
@字段。每个do | f|
如果f.length>0
@“建筑数据详细信息”栏do |表|
$row_num=0
额外计量单位=新计量单位
列=[]@columns.each{| s | columns u styles_hash[:heading_cell]
$row_num+=1
sheet.add_行[]
$row_num+=1
sheet.add_行[]
$row_num+=1
表.合并单元(“A2:Q2”)
新列

new_columns\up>当ruby进程内存不足时,它会从名为heap slab的系统中访问大量内存。然后,这个大内存块会在内部划分为许多小内存块,用于保存变量和代码。当您将nil赋值给某个变量时,垃圾收集器会将这个小内存块标记为空,但整个slab永远不会被删除返回到系统,直到进程终止。

我不确定这是否真的是您遇到的问题,但内存中分配的本应“短期”的对象最终意外升级为“长期”相反,由于垃圾收集器的运行频率不足以清理这些对象,导致内存膨胀:

Ruby 2.1中世代GC的作者Koichi Sasada:

“一些‘短寿命’的年轻对象将意外升级为‘老代’……如果这些‘短寿命’对象占用大量内存,我们需要释放这些对象。”

Ruby社区现在经常提到的一个问题是更改默认Ruby设置,以便告诉它更频繁地进行垃圾收集:

预期Ruby 2.1.1的内存会加倍。对此不满意吗?您有两个选择:

>p>通过减少<代码> RuyyGcHePaPoLoOdObjult.LimiTimeFase来调整它。在<代码> 1 /代码>下,您的内存消耗将与2相同。它与<代码> 2 <代码>默认>

  • 选项2,等待Ruby的未来版本,这将在2.2中修复,甚至可能在2.1.2中进行更多修补。请参阅:


  • 您是否能够用我们可以查看的小样本代码来复制问题?小样本代码也能正常工作。内存仍在使用中。请让我们看看您在样本代码中使用了什么?