Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 将数组置零后不会释放Ruby内存_Ruby On Rails_Arrays_Ruby_Memory - Fatal编程技术网

Ruby on rails 将数组置零后不会释放Ruby内存

Ruby on rails 将数组置零后不会释放Ruby内存,ruby-on-rails,arrays,ruby,memory,Ruby On Rails,Arrays,Ruby,Memory,我认为用下面的例子来说明我的问题更容易: 我使用的是纯Ruby2.2.2,但Rails4.2.2上也会出现这种情况 require 'bigdecimal' x = 20000000 第一种情况: big_number = BigDecimal.new(500) x.times {|i| @array << big_number } 另一个问题编辑为使用Yacine的评论。我尝试了你的代码,稍作修改以获得实时内存: def show_memory size = `ps ax

我认为用下面的例子来说明我的问题更容易:

我使用的是纯Ruby2.2.2,但Rails4.2.2上也会出现这种情况

require 'bigdecimal'
x = 20000000
第一种情况:

big_number = BigDecimal.new(500)
x.times {|i| @array << big_number }

另一个问题编辑为使用Yacine的评论。

我尝试了你的代码,稍作修改以获得实时内存:

def show_memory
  size = `ps ax -o pid,rss | grep -E "^[[:space:]]*#{$$}"`.strip.split.map(&:to_i)[1]
  puts "#{size}"
end

# Starts with the same 14 Mb on IRB
require 'bigdecimal'
x = 2000000
@array = []

show_memory

x.times {|i| @array << BigDecimal.new(500) }

show_memory

# The used memory is now about 760Mb
@array = nil
GC.start
show_memory
正如你所看到的,它在成长。。。保持在600Mb

如果您计划有很多ruby进程,但没有太多的RAM来处理它们,那么这仍然是一个问题。也许这个“细胞”可以配置,但我不知道


希望它能帮助你

需要区分内存释放的含义:

  • 垃圾回收后VM中未使用的内存

    在这两个示例中,垃圾收集器实际上释放了以前分配的内存。您可以使用
    ObjectSpace
    方法检查自己,如
    .count\u objects
    .count\u objects\u size
    .memsize\u of_all
    等。 您可能会看到
    T_DATA
    对象的增加,并在
    GC.start
    之后返回到以前的值。这同样适用于总消耗内存

  • 从VM到底层操作系统的未使用内存

    发生这种情况时仍然有点神秘,据我所知,在标准Ruby中没有办法手动调用它。 Ruby的VM(YARV)为下一次分配保留了先前GCed的可用内存,以便更有效地完成,然后再次从操作系统获取

    顺便说一句,第一个例子的工作原理是相同的,被错误地识别为返回初始状态。与第一种情况不同的是,只创建了一个对象
    big_number=BigDecimal.new(500)
    ,第二种情况下创建了2000万个对象。即使在第一个示例中,您也可能会看到RSS内存的明显增加,大约是通过从每个元素引用同一对象的数组大小来增加的


此外,两者都是特定于实现和操作系统的。

目前,我认为真正将内存释放回操作系统的唯一组合是IBM J9上的JRuby。JRuby确实将内存释放回JVM,我认为J9将内存释放回操作系统。AFAIK、Oracle HotSpot和Oracle JRockit没有。Rubinius可能会,我不确定。你是如何衡量“已用内存”的?在实际案例中,通过延迟的作业过程,以及在ruby过程的测试中。我将编辑问题以显示这一点。可能是关于该主题的必读书籍。它包含与OP中类似的示例,并对行为进行了很好的解释。非常有趣的文章。谢谢@joanbm。我没想到,保留时间这么长。谢谢你,亚辛,但我不明白如果把数字放进变量,为什么会释放内存。如果我这样做:hash=BigDecimal.new(500)x.times{| i | array这应该是特定于操作系统的,因为在我的Mac上,这两种方法都会扩大内存堆。无论如何,正如@joanbm所解释的,内存在Ruby上下文中被释放,而它仍然分配给Ruby VM。我知道Java VM也会这样做。这对你来说是个问题吗?你能解释一下这种行为有什么问题吗?也许我可以帮你解决这个问题a有一个大任务,它将运行几分钟,完成这个任务后,我需要内存来处理另一个进程。目前我正在重新启动ruby进程,但我正在寻找一个最佳解决方案。我们在生产中添加了一些类似的问题,我们使用Rails应用程序来构建巨大的excel文件,内存一直增加到~700Mb。由于多服务器和反向代理配置,它可以在每个服务器实例处理其中一个文件后爆炸内存。我们的解决方案是设置规则重新启动太大的进程,遗憾的是没有那么干净,但它工作得很好。好的,我清楚地理解VM对内存的使用,问题是虚拟机中未使用的内存。在我的情况下,我需要将此内存用于另一个进程,而不是在虚拟机中重用。服务器上的主要进程是Rails应用程序,但我有一个有时会运行的大任务(后台作业),但该进程本身不能长时间保留内存。@Peters如果运行内存密集型后台作业,为什么不在分叉进程中运行它?它不会以任何方式影响主进程的分配,所有内存在退出后会立即回收到操作系统。另一个问题,您能保证内存只会峰值一次吗将来任何时候都不需要?如果不需要,如何解决目前可用内存不足的情况?我也欢迎强制从VM释放保留内存的选项,但如果您想一想,这在实践中几乎没有用处。
def show_memory
  size = `ps ax -o pid,rss | grep -E "^[[:space:]]*#{$$}"`.strip.split.map(&:to_i)[1]
  puts "#{size}"
end

# Starts with the same 14 Mb on IRB
require 'bigdecimal'
x = 20000000

puts "With variable"
5.times {
  array = []
  hash = BigDecimal.new(500)
  x.times {|i| array << hash }
  show_memory
  array = nil
  GC.start
  show_memory
}

puts "\nWithout variable"
y = x/20
5.times {
  array = []
  y.times {|i| array << BigDecimal.new(500) }
  show_memory
  array = nil
  GC.start
  show_memory
}
With variable
165448
9460
165564
9464
165564
9464
165564
9464
165564
9464

Without variable
158068
150388
167016
167016
167016
167016
167016
167016
167016
167016
def show_memory
  size = `ps ax -o pid,rss | grep -E "^[[:space:]]*#{$$}"`.strip.split.map(&:to_i)[1]
  puts "#{size}"
end

# Starts with the same 14 Mb on IRB
require 'bigdecimal'
x = 2000000
@array = []

show_memory

x.times {|i| @array << BigDecimal.new(500) }

show_memory

# The used memory is now about 760Mb
@array = nil
GC.start
show_memory
def show_memory
  size = `ps ax -o pid,rss | grep -E "^[[:space:]]*#{$$}"`.strip.split.map(&:to_i)[1]
  puts "#{size}"
end

# Starts with the same 14 Mb on IRB
require 'bigdecimal'
x = 2000000

50.times {
  @array = []
  x.times {|i| @array << BigDecimal.new(500) }
  show_memory
  @array = nil
  GC.start
  show_memory
}
312508
278500
348688
331172
361208
359160
391664
386544
415280
414264
444316
441244
458152
448744
466632
464584
480320
479192
498196
495132
514208
514208
530620
529596
553976
551284
567784
565736
582284
579212
595224
589080
616952
607820
613300
594588
602404
586776
602612
601588
618032
602404
618440
594628
609512
593884
609724
590000
606972
591352
607236
590584
606276
590648
606284
588608
604272
587620
607452
591824
608428
590752
606852
588152
603820
583072
604672
598596
599892
584264
591904
575252
592588
592588
608808
593188
609244
592592
609572
593236
615500
598848
615452
597776
614124
587240
608284
583448
600004
584376
600052
581352
598748
583128
599984
584356
...