Waarom is het geen goed idee om dynamisch veel symbolen in robijn te maken (voor versies vóór 2.2)?

Wat is de functie van het symbool in robijn? wat is het verschil tussen string en symbool?
Waarom is het geen goed idee om veel symbolen dynamisch te maken?


Antwoord 1, autoriteit 100%

Symbolen zijn als tekenreeksen, maar ze zijn onveranderlijk – ze kunnen niet worden gewijzigd.

Ze worden maar één keer in het geheugen geplaatst, waardoor ze zeer efficiënt zijn om te gebruiken voor zaken als sleutels in hashes, maar ze blijven in het geheugen totdat het programma wordt afgesloten. Dit maakt ze een geheugenzwijn als je ze misbruikt.

Als u dynamisch veel symbolen maakt, wijst u veel geheugen toe dat pas kan worden vrijgemaakt als uw programma is afgelopen. U moet alleen dynamisch symbolen maken (met behulp van string.to_sym) als u weet dat u:

  1. moet herhaaldelijk toegang krijgen tot het symbool
  2. hoeft ze niet te wijzigen

Zoals ik al eerder zei, zijn ze handig voor zaken als hashes – waarbij je meer om de identiteitvan de variabele geeft dan om de waarde ervan. Symbolen zijn, indien correct gebruikt, een leesbare en efficiënte manier om identiteit door te geven.

Ik zal je reactie uitleggen wat ik bedoel over de onveranderlijkheid van symbolen.

Strings zijn als arrays; ze kunnen ter plekke worden gewijzigd:

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> 

Symbolen lijken meer op getallen; ze kunnen niet op hun plaats worden bewerkt:

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

Antwoord 2, autoriteit 10%

Een symbool is hetzelfde object en dezelfde toewijzing van geheugen, ongeacht waar het wordt gebruikt:

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

Twee strings die ‘hetzelfde’ zijn omdat ze dezelfde karakters bevatten, verwijzen mogelijk niet naar hetzelfde geheugen, wat inefficiënt kan zijn als je strings gebruikt voor bijvoorbeeld hashes.

Symbolen kunnen dus handig zijn om de geheugenoverhead te verminderen. Ze zijn echter een geheugenlek dat wacht om te gebeuren, omdat symbolen niet kunnen worden verzameld als ze eenmaal zijn gemaakt. Door duizenden en duizenden symbolen te maken, wordt het geheugen toegewezen en kan het niet worden hersteld. Hoera!


Antwoord 3, autoriteit 6%

Het kan bijzonder slecht zijn om symbolen van gebruikersinvoer te maken zonder de invoer te valideren tegen een soort witte lijst (bijvoorbeeld voor queryreeksparameters in RoR). Als gebruikersinvoer wordt geconverteerd naar symbolen zonder validatie, kan een kwaadwillende gebruiker ervoor zorgen dat uw programma grote hoeveelheden geheugen in beslag neemt dat nooit zal worden verzameld.

Slecht (er wordt een symbool gemaakt ongeacht de invoer van de gebruiker):

name = params[:name].to_sym

Goed (een symbool wordt alleen gemaakt als de gebruikersinvoer is toegestaan):

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

Antwoord 4, autoriteit 5%

Begint Ruby 2.2en hoger Symbolenworden automatisch verzameld en dus dit zou geen probleem moeten zijn.


Antwoord 5, autoriteit 2%

Als je Ruby 2.2.0 of hoger gebruikt, zou het normaal gesproken OK moeten zijn om dynamisch veel symbolen te maken, omdat ze worden verzameld volgens de Ruby 2.2.0-preview1 aankondiging, met een link naar meer details over het nieuwe symbool GC. Als u uw dynamische symbolen echter doorgeeft aan een soort code die deze omzet in een ID (een intern Ruby-implementatieconcept dat wordt gebruikt in de C-broncode), wordt deze in dat geval vastgezet en wordt er nooit afval verzameld. Ik weet niet zeker hoe vaak dat gebeurt.

Je kunt symbolen zien als een naam van iets, en strings (ruwweg) als een reeks tekens. In veel gevallen kunt u een symbool of een tekenreeks gebruiken, of u kunt een combinatie van beide gebruiken. Symbolen zijn onveranderlijk, wat betekent dat ze niet kunnen worden gewijzigd nadat ze zijn gemaakt. De manier waarop symbolen worden geïmplementeerd, is zeer efficiënt om twee symbolen te vergelijken om te zien of ze gelijk zijn, dus het gebruik ervan als sleutels voor hashes zou iets sneller moeten zijn dan het gebruik van strings. Symbolen hebben niet veel van de methoden die strings hebben, zoals start_with?, dus je zou to_smoeten gebruiken om het symbool in een string te converteren voordat je die methoden aanroept.

Je kunt hier meer lezen over symbolen in de documentatie:

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

Other episodes