• S
    Freeze string literals when not mutated. · 5bb1d4d2
    schneems 提交于
    I wrote a utility that helps find areas where you could optimize your program using a frozen string instead of a string literal, it's called [let_it_go](https://github.com/schneems/let_it_go). After going through the output and adding `.freeze` I was able to eliminate the creation of 1,114 string objects on EVERY request to [codetriage](codetriage.com). How does this impact execution?
    
    To look at memory:
    
    ```ruby
    require 'get_process_mem'
    
    mem = GetProcessMem.new
    GC.start
    GC.disable
    1_114.times { " " }
    before = mem.mb
    
    after = mem.mb
    GC.enable
    puts "Diff: #{after - before} mb"
    
    ```
    
    Creating 1,114 string objects results in `Diff: 0.03125 mb` of RAM allocated on every request. Or 1mb every 32 requests.
    
    To look at raw speed:
    
    ```ruby
    require 'benchmark/ips'
    
    number_of_objects_reduced = 1_114
    
    Benchmark.ips do |x|
      x.report("freeze")    { number_of_objects_reduced.times { " ".freeze } }
      x.report("no-freeze") { number_of_objects_reduced.times { " " } }
    end
    ```
    
    We get the results
    
    ```
    Calculating -------------------------------------
                  freeze     1.428k i/100ms
               no-freeze   609.000  i/100ms
    -------------------------------------------------
                  freeze     14.363k (± 8.5%) i/s -     71.400k
               no-freeze      6.084k (± 8.1%) i/s -     30.450k
    ```
    
    Now we can do some maths:
    
    ```ruby
    ips = 6_226k # iterations / 1 second
    call_time_before = 1.0 / ips # seconds per iteration 
    
    ips = 15_254 # iterations / 1 second
    call_time_after = 1.0 / ips # seconds per iteration 
    
    diff = call_time_before - call_time_after
    
    number_of_objects_reduced * diff * 100
    
    # => 0.4530373333993266 miliseconds saved per request
    ```
    
    So we're shaving off 1 second of execution time for every 220 requests. 
    
    Is this going to be an insane speed boost to any Rails app: nope. Should we merge it: yep. 
    
    p.s. If you know of a method call that doesn't modify a string input such as [String#gsub](https://github.com/schneems/let_it_go/blob/b0e2da69f0cca87ab581022baa43291cdf48638c/lib/let_it_go/core_ext/string.rb#L37) please [give me a pull request to the appropriate file](https://github.com/schneems/let_it_go/blob/b0e2da69f0cca87ab581022baa43291cdf48638c/lib/let_it_go/core_ext/string.rb#L37), or open an issue in LetItGo so we can track and freeze more strings. 
    
    Keep those strings Frozen
    
    ![](https://www.dropbox.com/s/z4dj9fdsv213r4v/let-it-go.gif?dl=1)
    5bb1d4d2
log_subscriber.rb 2.4 KB