为什么在ruby中dynamic创build大量符号并不是一个好主意?

符号在ruby中的function是什么? string和符号有什么区别? 为什么dynamic创build大量符号并不是一个好主意?

符号就像string,但它们是不可变的 – 它们不能被修改。

它们只会被记忆一次,使得它们非常有效地用于诸如哈希键之类的事物,但是它们会留在内存中,直到程序退出。 这使他们成为一个记忆猪,如果你滥用他们。

如果dynamic地创build大量符号,则会分配大量内存,在程序结束之前无法释放内存。 如果您知道您将:只应dynamic创build符号(使用string.to_sym ):

  1. 需要重复访问该符号
  2. 不需要修改它们

正如我前面所说的,它们对于哈希这样的事情是有用的 – 在这里你更关心variables的身份而不是它的价值。 正确使用符号是一种可读和有效的方式来传递身份。

我将解释我的意思是关于你的评论符号的不变性。

string就像数组; 他们可以在适当的地方修改:

 12:17:44 ~$ irb irb(main):001:0> string = "Hello World!" => "Hello World!" irb(main):002:0> string[5] = 'z' => "z" irb(main):003:0> string => "HellozWorld!" irb(main):004:0> 

符号更像数字; 他们不能被编辑:

 irb(main):011:0> symbol = :Hello_World => :Hello_World irb(main):012:0> symbol[5] = 'z' NoMethodError: undefined method `[]=' for :Hello_World:Symbol from (irb):12 from :0 

符号是相同的对象和相同的内存分配,不pipe它在哪里使用:

 >> :hello.object_id => 331068 >> a = :hello => :hello >> a.object_id => 331068 >> b = :hello => :hello >> b.object_id => 331068 >> a = "hello" => "hello" >> a.object_id => 2149256980 >> b = "hello" => "hello" >> b.object_id => 2149235120 >> b = "hell" + "o" 

两个“相同”的string,它们包含相同的字符,可能不会引用相同的内存,如果您使用string进行哈希,这可能是低效的。

所以,符号可以用来减less内存开销。 但是 – 这是一个内存泄漏等待发生,因为符号不能被垃圾回收一旦创build。 创build数千和数千个符号将分配内存并且不可恢复。 哎呀!

从用户input创build符号而不validation某些白名单的input(例如,RoR中的查询string参数)可能尤其不利。 如果用户input未经validation转换为符号,恶意用户可能会导致您的程序消耗大量内存,永远不会进行垃圾回收。

坏(不pipe用户input,都会创build一个符号):

 name = params[:name].to_sym 

好(只有在允许用户input时才会创build符号):

 whitelist = ['allowed_value', 'another_allowed_value'] raise ArgumentError unless whitelist.include?(params[:name]) name = params[:name].to_sym 

如果您使用的是Ruby 2.2.0或更高版本,那么dynamic创build大量符号通常应该是可以的,因为它们会根据Ruby 2.2.0-preview1通知进行垃圾回收,该通知链接了更多关于新的符号GC 。 但是,如果您将dynamic符号传递给某种将其转换为ID(C源代码中使用的内部Ruby实现概念)的代码,那么在这种情况下,它将被固定并永远不会被垃圾收集。 我不确定这种情况发生的频率如何。

你可以把符号看作某种东西的名称,把string(粗略地)看作是一系列字符。 在许多情况下,你可以使用符号或string,或者你可以使用两者的混合物。 符号是不可变的,这意味着它们在创build后不能被改变。 符号被实现的方式,比较两个符号以查看它们是否相等是非常有效的,因此将它们用作哈希的关键字应该比使用string要快一些。 符号没有很多string做的方法,比如start_with? 因此在调用这些方法之前,必须使用to_s将该符号转换为string。

您可以在文档中阅读关于符号的更多信息:

http://www.ruby-doc.org/core-2.1.3/Symbol.html

启动Ruby 2.2及更高版本符号会自动收集垃圾,所以这不应该成为问题。