为什么用ruby动态创建大量符号不是一个好主意(对于2.2之前的版本)?

0aydgbwb  于 2023-02-18  发布在  Ruby
关注(0)|答案(5)|浏览(114)

符号在ruby中的作用是什么?字符串和符号有什么区别?为什么动态创建大量符号不是一个好主意?

uxhixvfz

uxhixvfz1#

符号就像字符串,但它们是不可变的--不能修改。
它们只被放入内存一次,这使得它们在处理哈希值中的密钥等事情时非常有效,但它们会一直留在内存中直到程序退出,如果你误用它们,这会使它们占用大量内存。
如果动态创建大量符号,则会分配大量内存,这些内存在程序结束之前无法释放(edit:不再是since Ruby 2.2的情况)。只有当您知道将执行以下操作时,才应动态创建符号(使用string.to_sym):
1.需要重复访问符号
1.不需要修改它们
正如我之前所说的,符号对于像散列这样的东西很有用--在这种情况下,你更关心变量的标识,而不是它的值。符号,如果使用得当,是传递标识的一种可读和有效的方式。
我将解释我的意思是什么不变性的符号回复您的评论。
字符串就像数组;它们可以在适当的位置进行修改:

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
8zzbczxx

8zzbczxx2#

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

>> :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"

两个“相同”的字符串,因为它们包含相同的字符,可能不会引用相同的内存,如果你使用字符串,比如说,散列,这可能是低效的。
因此,符号可以有效地减少内存开销。然而,它们是一个等待发生的内存泄漏,因为符号一旦创建就不能被垃圾收集。创建成千上万的符号将分配内存,并且不可恢复。哎呀!

yb3bgrhw

yb3bgrhw3#

从用户输入创建符号而不验证输入是否符合某种白名单(例如,RoR中的查询字符串参数)是非常糟糕的。如果用户输入在没有验证的情况下转换为符号,恶意用户可能会导致程序消耗大量内存,而这些内存永远不会被垃圾收集。
错误(无论用户输入如何,都会创建符号):

name = params[:name].to_sym

良好(仅当允许用户输入时才创建符号):

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

yjghlzjz4#

Starting Ruby 2.2及更高版本Symbols会自动进行垃圾收集,因此这不应成为问题。

7jmck4yq

7jmck4yq5#

如果您使用的是Ruby 2.2.0或更高版本,动态创建大量符号通常是可以的,因为它们将根据Ruby 2.2.0-preview1 announcement进行垃圾收集,Ruby 2.2.0-preview1 announcement具有到more details about the new symbol GC的链接。(C源代码中使用的一个内部Ruby实现概念),那么在这种情况下,它将被固定,永远不会被垃圾收集。
你可以把符号看作是某个东西的名字,而字符串(大致)表示为字符序列。在许多情况下,您可以使用符号或字符串,或者可以使用两者的混合。符号是不可变的,这意味着它们在创建后不能更改。符号的实现方式是,比较两个符号以查看它们是否相等是非常有效的。所以用它们作为哈希的键应该比用字符串快一些,Symbols没有字符串的很多方法,比如start_with?,所以在调用这些方法之前,你必须用to_s把符号转换成字符串。
您可以在文档中阅读有关符号的详细信息:
http://www.ruby-doc.org/core-2.1.3/Symbol.html

相关问题