26

Ruby 是否在堆上分配所有内容,或者是否有任何实例将某些内容存储在堆栈上?我的印象是所有变量本质上都在堆栈上,并且包含对堆上对象的透明引用。我的这种想法正确吗?这个实现是特定的吗?

此外,如果变量在堆栈上分配并且仅包含隐藏指针,那么变量本身(不考虑它们指向的对象)消耗多少字节?

编辑:

之所以问这个问题,是因为我试图弄清楚光纤的 4kB 堆栈限制是否会成为这个问题的一个问题。似乎(使用 MRI 1.9.3)每个变量本身消耗一个字节,并且与光纤相关的轻微开销将可用堆栈大小减少了几个字节。

此代码将在第 4,045 次迭代时失败:

count = 0
loop do
  count += 1
  puts count
  varlist = String.new
  count.times do |i|
    varlist += "a#{i} = 1\n"
  end
  s = "fiber = Fiber.new do \n #{varlist} \n end \n fiber.resume"
  eval(s)
end
4

1 回答 1

21

这取决于 Ruby 的实现。

例如,Ruby 2.0 MRI(大多数系统上的典型MRI)将其所有对象存储在堆中。诸如短弦之类的小物体可以完全放入堆中。对于大型对象,Ruby 会在堆之外分配额外的内存。

请参阅“MRI 内存分配 - 开发人员入门”“揭开 Ruby GC 的神秘面纱”

这是“了解 Ruby 如何在内存中存储对象”,它有一个很棒的、更长的描述:

“对象在内存中占用的整个空间并不存储在 Slot 内。相反,每个 Slot 都是一个固定大小的小空间,可以认为是 Ruby 解释器处理内存中的一个位置。这个位置存在于 Ruby Heap 之外本身并包含对象的真正“肉”。要清楚,如果你有一个 50MB 的字符串 - 50MB 的数据存储在 Ruby 的堆之外。如果你真的想知道 50MB 的故事,它的空间实际上是由 C 中的 malloc 命令之类的东西分配的(就像好的 ol' Ruby 是用 C 编写的)然后存储在系统堆中。Ruby 堆中的 Slot 只包含对系统堆上该内存位置的引用,其中包含50MB 的数据。”

“Ruby 有自己的堆管理,实际上由几个 'Ruby 堆' 组成,用于管理在 Ruby 程序执行期间创建的对象;这与操作系统的系统堆是分开的。每个单独的 Ruby 堆都包含插槽,每个插槽能够一个引用一个对象。

另一个很好的来源是“ How Ruby Manages Memory and Garbage Collection ”,它链接到“ Garbage Collection Slides from LA Ruby Conference ”的幻灯片。

“作为一种垃圾收集语言,Ruby 采取了简单的方法,将所有内容都放在堆上”。

纤维

Ruby 中的 Fiber 很特别,因为每个 Fiber 都有自己的小堆栈。

“与其他无堆栈轻量级并发模型相反,每个光纤都带有一个 4KB 的小堆栈。这使得光纤能够从光纤块内的深层嵌套函数调用中暂停。”

您可能对动态光纤堆栈大小的长期运行功能请求感兴趣。

如果您对现实世界的解决方案更感兴趣,功能请求作者推荐这种解决方法:“重构需要大堆栈在单独线程中运行然后阻塞 thread.value 的操作。”

cont.c您还可以考虑在源文件中使用自己选择的 FIBER_MACHINE_STACK_ALLOCATION_SIZE 和 FIBER_VM_STACK_SIZE 来编译自定义版本的 Ruby 。该文件还显示了如何分配、释放光纤堆栈等。

于 2012-11-30T05:00:46.473 回答