Ruby是否在堆上分配所有内容,或者是否有任何存储在堆栈中的实例?我的印象是所有变量基本上都在堆栈上,并且包含对堆上对象的透明引用。我这个想法是否正确?这个实现是否具体?
另外,如果是在堆栈上分配变量并且仅包含隐藏指针的情况,那么变量本身(忽略它们指向的对象)消耗了多少字节?
编辑:
这个问题被问到了,因为我试图弄清楚光纤的4kB堆栈限制是否会成为this question中的一个问题。似乎(使用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
答案 0 :(得分:19)
这取决于Ruby实现。
例如,Ruby 2.0 MRI(大多数系统中的典型)将所有对象存储在堆中。诸如短弦之类的小物体可以完全装入堆中。对于大型对象,Ruby会在堆外部使用malloc额外的内存。
请参阅"MRI Memory Allocation - A Primer For Developers"和"Demystifying the Ruby GC"
这里的"Understanding How Ruby Stores Objects In Memory"有一个很棒的,更长的描述:
“对象占用内存的整个空间不存储在Slot内。而是每个Slot都是一个小的固定大小的空间,可以被认为是Ruby解释器处理内存中的一个位置。这个位置存在于Ruby Heap本身并包含对象的真正“肉”。要清楚,如果你有一个50MB的字符串 - 50MB的数据存储在Ruby的堆之外。如果你真的想知道50MB的故事,它的空间实际上是由C语言中的malloc命令分配的(好的'Ruby用C编写),然后存储在系统堆中.Ruby堆中的Slot只包含对系统内存位置的引用堆包含50MB的数据。“
“Ruby拥有自己的堆管理,它实际上包含几个'Ruby Heaps'来管理在Ruby程序执行期间创建的对象;这与操作系统的System Heap是分开的。每个Ruby Heap都包含Slots,每个Slot都可以引用一个对象。
另一个好的来源是“How Ruby Manages Memory and Garbage Collection”,它链接到“Garbage Collection Slides from LA Ruby Conference”的幻灯片。
“作为一种垃圾收集语言,Ruby通过将所有内容放在堆上来实现简单的路径”。
光纤在Ruby中是特殊的,因为每根光纤都有自己的小堆栈。
“与其他无堆栈轻量级并发模型相比,每根光纤都带有一个4KB的小堆栈。这使得光纤可以通过光纤模块中深度嵌套的函数调用暂停。”
您可能对长期运行的feature request动态光纤堆栈大小感兴趣。
如果您对实际解决方案更感兴趣,则功能请求作者建议使用此解决方法:“重构需要大量堆栈在单独线程中运行然后在thread.value上阻塞的操作。”
您还可以考虑使用您自己的cont.c
源文件中的FIBER_MACHINE_STACK_ALLOCATION_SIZE和FIBER_VM_STACK_SIZE选项来编译自定义版本的Ruby。该文件还显示了如何分配,释放光纤堆栈等。