为什么在ruby中动态创建大量符号不是一个好主意?

Ikb*_*ear 61 ruby string symbols

红宝石中符号的功能是什么?字符串和符号之间有什么区别?为什么动态创建大量符号不是一个好主意?

dav*_*dev 88

符号就像字符串,但它们是不可变的 - 它们不能被修改.

它们只被放入内存中一次,使得它们非常有效地用于哈希中的键,但它们会留在内存中直到程序退出.如果你滥用它们,这会让它们变成记忆力.

如果动态创建大量符号,则会分配大量内存,直到程序结束才能释放.string.to_sym如果您知道,您应该只动态创建符号(使用):

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

正如我之前所说,它们对哈希这样的东西很有用 - 你更关心变量的身份而不是它的价值.正确使用符号时,符号是一种可读且有效的传递身份的方式.

我将解释我对你的评论的符号的不变性的意思.

字符串就像数组; 它们可以在适当的位置修改:

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> 
Run Code Online (Sandbox Code Playgroud)

符号更像是数字; 他们无法编辑到位:

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
Run Code Online (Sandbox Code Playgroud)


ste*_*tef 9

无论在何处使用,符号都是相同的对象和相同的内存分配:

>> :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"
Run Code Online (Sandbox Code Playgroud)

两个字符串"相同",因为它们包含相同的字符,可能不会引用相同的内存,如果您使用字符串,例如哈希值,这可能效率低下.

因此,符号可用于减少内存开销.但是 - 它们是等待发生的内存泄漏,因为一旦创建符号就不能进行垃圾回收.创建成千上万的符号将分配内存而不是可恢复的.哎呀!


Rob*_*jic 6

从用户输入创建符号而不根据某种白名单验证输入(例如,对于RoR中的查询字符串参数)可能特别糟糕.如果用户输入转换为符号而未经验证,则恶意用户可能会导致程序消耗大量内存,而这些内存永远不会被垃圾回收.

错(无论用户输入如何,都会创建一个符号):

name = params[:name].to_sym
Run Code Online (Sandbox Code Playgroud)

好(只有在允许用户输入的情况下才会创建符号):

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


sid*_*idj 5

从 Ruby 2.2及更高版本开始符号会自动进行垃圾收集,因此这应该不是问题。