Hoje fiz vários testes de gerência de memória e achei interessante como cada ganho de byte pode ser interessante conforme a quantidade de dados que se tem para manusear. Apesar da memória ser barata, tratando-se de performance e escalabilidade o barato sai caro muitas vezes.

Então olhando para os gargalos do sistema observei um hash muito utilizado em um determinado sistema e então resolvi montar esta comparação.

A brincadeira começa com uma simples array de 1000_000 registros e populamos ela das seguintes formas:

Hash - memory_a.rb

a = []
sum = 0
100000.times do |i|
   sum += 1
   a << {:i => i,
         :sum => sum}

end

Struct - memory_b.rb

a = []
B = Struct.new :i, :sum
sum = 0
100000.times do |i|
    sum += 1
    a << B.new(i,sum)
end

Array - memory_c.rb

i = []
sums = []
sum = 0
100000.times do |i|
    sum += 1
    i << i
    sums << sum
end

Class com métodos - memory_d.rb

a = []
class B
  def initialize i, sum
    @i = i
    @sum = sum
  end
  def i
    @i
  end
  def sum
    @sum
  end
end
sum = 0
100000.times do |i|
  sum += 1
   a << B.new(i,sum)
end

Class com accessors - memory_e.rb

a = []
sum = 0
class B
  attr_accessor :i, :sum
  def initialize i, sum
    @i = i
    @sum = sum
  end
end
100000.times do |i|
  sum += 1
  a << B.new(i,sum)
end

Class sem métodos - memory_f.rb

class B
  instance_methods.each { |m| undef_method m unless m =~ /^__|object_id/ }
  attr_accessor :i, :sum
  def initialize i, sum
    @i = i
    @sum = sum
  end
end

a = []
sum = 0
100000.times do |i|
  sum += 1
  a << B.new(i,sum)
end

Observando os resultados com jruby-1.7.3 temos os seguintes tamanhos de memória em bytes:

arquivo memória
memory_a.rb 106409984
memory_b.rb 94859264
memory_c.rb 95125504
memory_d.rb 95064064
memory_e.rb 94691328
memory_f.rb 94236672

No meu caso o modelo memory_f parece ser o mais adequado em vista do consumo de memória e a implementação também é relativamente simples. O interessante destes objetos em branco é por que de certa forma eles não podem ser clonados, mas para casos específicos podem ajudar muito, neste caso têm uma significância de aproximadamente 12%.

Baixe e teste o code você mesmo!

Assim que sobrar um tempo vou evoluir os modelos para comparar entre tipos de númericos. Hoje estamos usando o java.math.BigDecimal para cálculos precisos mas este é um dos mais lentos e grandes para trabalhar com números.


Share → Twitter Facebook Linkedin


Hello there, my name is Jônatas Davi Paganini and this is my personal blog.
I'm developer advocate at Timescale and I also have a few open source projects on github.

Check my talks or connect with me via linkedin / twitter / github / instagram / facebook / strava / meetup.