我可以在不复制的情况下更改冻结字符串的编码吗



字符串及其重复项是否可以共享相同的底层内存?有用Ruby写的副本吗?

我有一个大的、冻结的字符串,我想更改它的编码。但我不想为了这么做而复制整个字符串。对于上下文,这是将值传递给Google协议缓冲区,该缓冲区具有bytes类型,并且只接受Encoding::ASCII_8BIT。

big_string.freeze
MyProtobuf::SomeMessage.new(
# I would prefer not to have to copy the whole string just to
# change the encoding.
value: big_string.dup.force_encoding(Encoding::ASCII_8BIT)
)

它似乎对我来说很好:(使用MRI/YARV 1.9,2.x,3.x)

require 'objspace'
big_string = Random.bytes(1_000_000).force_encoding(Encoding::UTF_8)
big_string.encoding #=> #<Encoding:UTF-8>
big_string.bytesize #=> 1000000
ObjectSpace.memsize_of(big_string) #=> 1000041

dup_string = big_string.dup.force_encoding(Encoding::ASCII_8BIT)
dup_string.encoding #=> #<Encoding:ASCII-8BIT>
dup_string.bytesize #=> 1000000
ObjectSpace.memsize_of(dup_string) #=> 40

这40个字节是Ruby中容纳一个对象(RVALUE)的大小。

注意,除了dup/force_encoding(Encoding::ASCII_8BIT),还有b,它立即返回二进制编码的副本。

为了获得更深入的信息,这里有一篇2012年(Ruby 1.9)的博客文章,内容是Ruby中的写时复制/共享字符串:

  • 看到双重:Ruby如何共享字符串值

摘自作者的《显微镜下的红宝石》一书:(第265页)

在内部,JRuby和MRI都对字符串和其他数据使用名为写时复制的优化。这个技巧允许两个相同的字符串值共享相同的数据缓冲区,这既节省了内存又节省了时间,因为Ruby避免了不必要地对相同的字符串数据进行单独复制。

字符串及其重复项是否可以共享相同的底层内存?有用Ruby写的副本吗?

Ruby语言规范中没有任何内容可以阻止这种情况。Ruby语言规范中也没有强制执行这一点。

一般来说,Ruby语言规范试图对所有与内存管理、空间复杂性、步骤复杂性或时间复杂性相关的事情保持沉默。这并不是Ruby语言规范独有的,大多数语言规范都试图给实现者留下尽可能多的余地。换句话说,语言规范倾向于指定语法语义,并将语用学留给实现者。(C++在某种程度上是一个例外,因为它为标准库中的算法指定了空间和时间的复杂性。)即使是C,通常被认为是一种可以让你完全控制一切的语言,实际上也没有精确地指定内存布局之类的东西——例如,由于标准中术语width的定义,CCD_ 5实际上被允许占用超过16个比特!

每个实现者都可以自由地实现字符串,只要它们符合Ruby语言规范中定义的语义。

如果我没记错的话,Rubinius和TruffleRuby都曾经尝试过基于Ropes的String实现。TruffleRuby的首席开发人员Chris Seaton写了一篇关于该实现的论文。然而,我不知道他们是否仍在使用它。(我知道TruffleRuby最近改用了TruffleStrings,我不确定他们的底层表示是什么……或者他们是否保证了特定的底层表示。)

答案";您必须查看规范";,不过:不幸的是,与许多其他编程语言不同,Ruby语言规范并不是作为一个单独的文档存在于一个地方。Ruby没有一个形式化的规范来定义某些语言结构的含义。

有几个资源,它们的总和可以被认为是Ruby编程语言的一种规范。

其中一些资源是:

  • ISO/IEC 30170:2012信息技术——编程语言——Ruby规范——请注意,ISO Ruby规范是在2009-2010年左右编写的,其具体目标是当时所有现有的Ruby实现都很容易兼容。由于YARV和MacRuby只实现Ruby 1.9+,MRI只实现Ruby 1.8及更低版本,而JRuby、XRuby、Ruby.NET和IronRuby(当时)只实现了Ruby 1.8的一个子集,这意味着ISO Ruby规范只包含Ruby 1.8和Ruby 1.9共有的功能。此外,ISO Ruby规范是专门设计成最小的,并且只包含编写Ruby程序绝对需要的功能。因此,例如,它只非常广泛地指定了String(因为它们在Ruby 1.8和Ruby 1.9之间发生了显著变化)。显然,它也没有指定在编写ISO Ruby规范之后添加的功能,如Ractor或Pattern Matching
  • Ruby规范套件(又名ruby/spec)—请注意,不幸的是,ruby/spec还远远没有完成。然而,我很喜欢它,因为它是用Ruby写的,而不是";ISO标准";,对于Rubister来说,它更容易阅读,而且它兼作可执行一致性测试套件
  • David Flanagan和Yukihiro‘matz’Matsumoto的Ruby编程语言——本书由David Flanagn和Ruby的创建者matz共同撰写,作为Ruby的语言参考
  • Dave Thomas、Andy Hunt和Chad Fowler的《编程Ruby》——这本书是第一本关于Ruby的英文书,长期以来一直是Ruby的标准介绍和描述。本书还首次记录了Ruby核心库和标准库,作者将这些文档捐赠给了社区
  • Ruby问题跟踪系统,特别是功能子跟踪器——然而,请注意,不幸的是,社区非常非常不善于区分Ruby编程语言的Tickets和YARV Ruby实现的Ticket:它们都混合在跟踪器中
  • Ruby开发者会议的会议日志。(同样的问题:Ruby和YARV混杂在一起。)
  • 邮件列表中经常讨论新功能,特别是ruby core(英语)和ruby dev(日语)邮件列表。(同样的问题再次出现。)
  • Ruby文档——同样,请注意,该文档是从YARV的源代码生成的,并没有区分Ruby的特性和YARV的特性
  • 在过去,有几次尝试将对Ruby规范的更改形式化,例如Ruby更改请求(RCR)和Ruby增强建议(REP)过程,但都没有成功
  • 如果所有其他方法都失败了,你需要检查流行的Ruby实现的源代码,看看它们实际上做了什么。请注意复数:你必须查看多个,最好是all的实现,才能弄清楚共识是什么。只看一个实现不可能告诉你你所看到的是这个特定实现的一个实现怪癖,还是Ruby语言的一种普遍认可的行为

最新更新