arrays - 为什么不保留空数组和哈希?
问题描述
最近我发现 Ruby 没有优化[]
并被{}
实习以指向一个公共的共享对象。演示:
irb(main):001:0> [].object_id
=> 70284401361960
irb(main):002:0> [].object_id
=> 70284392762340 # different
irb(main):003:0> [].object_id
=> 70284124310100 # different
irb(main):005:0> {}.object_id
=> 70284392857480
irb(main):006:0> {}.object_id
=> 70284392870480 # different
irb(main):007:0> {}.object_id
=> 70284392904360 # different
我知道通常使用空哈希和数组文字来初始化将立即变异的值。但是,即使您这样做[].freeze.object_id
或{}.freeze.object_id
相反,也会发生这种情况。
String
当 env varRUBYOPT
设置为时,将此与 进行对比--enable-frozen-string-literal
:
irb(main):001:0> ""
=> 70284400947400
irb(main):002:0> ""
=> 70284400947400 # same
irb(main):003:0> ""
=> 70284400947400 # same
即使您不启用冻结字符串文字,如果您"".freeze.object_id
改为调用,每次都会获得相同的对象 id,尽管我怀疑初始""
文字仍然分配了一个freeze
正在调用的中间字符串对象。
在对性能敏感的代码库中(好吧,作为对性能敏感的你可以让自己在仍然使用 MRI 的同时保持哈哈),我已经看到了这种解决方法,它使用以下共享常量代替[]
或{}
用于哈希或数组不的情况t 需要是可变的:
module LessAllocations
EMPTY_HASH = {}.freeze
EMPTY_ARRAY = [].freeze
# String literals are already frozen, use '' instead
# EMPTY_STRING = ''
end
所以我的问题是:
这是错失的优化机会吗?
似乎可以将窥视孔优化写入实习生冻结的空哈希或数组文字。需要成为语言语义的一部分,即是否存在任何可观察到的差异(显然除了 的行为
object_id
)?空散列和数组字面量是否由标记指针表示?他们甚至会导致任何分配发生吗?
解决方案
这是错失的优化机会吗?
要回答这个问题,必须对现实世界的内存使用情况进行调查,但我认为这不太可能。你可以做一个小实验...
class Array
EMPTY_ARRAY = [].freeze
def freeze
empty? ? EMPTY_ARRAY : super
end
end
空物体非常小。与您的程序使用内存的其他所有内容相比,拥有如此多的内存以致于它们使用大量内存是一种极端情况。
我知道通常使用空哈希和数组文字来初始化将立即变异的值。
出于这个原因,将写入时复制添加到空哈希和数组可能会减慢速度。
但即使您改为使用 [].freeze.object_id 或 {}.freeze.object_id 也会发生这种情况。
冻结它们意味着您提前知道它们将保持空置状态,这是极其罕见的。拥有这么多已知的空哈希和数组以致成为性能问题是一种极端情况。不断的变通方法似乎很好。
推荐阅读
- try-catch - Solidity try catch 显示 Etherscan 上内部 tx 的执行已恢复
- c++ - 在 ubuntu 上将默认 c++ 库从 std=c++14 切换到 std=c++17
- model-view-controller - 如何从 url 中删除 HOME 以获取除索引以外的操作结果
- javascript - 如何从输入类型“颜色”打印十六进制颜色
- javascript - 如果条件满足 JS,则拆分为单独的数组
- snowflake-cloud-data-platform - 雪花网络用户级策略
- kotlin - 希望一个简单的 Kotlin 关于循环通过回收器
- python - 错误“'模块'类型的参数不可迭代'
- python - 如果子字符串在列表中,则使用来自另一个熊猫列的子字符串创建新列
- npm - postcss-nested 和 autoprefixer 不工作