Go проти Ruby: Чому Go використовує значно менше пам’яті?

Коли я вирішував задачу перевірки, чи є число паліндромом, я реалізував однакову логіку як в Go, так і в Ruby. Результати були вражаючими — Go використав лише 6.03 MB пам'яті, тоді як Ruby спожив вражаючі 211.55 MB, що приблизно в 35 разів більше! Це змусило мене дослідити, чому Go є набагато більш ефективним за пам'яттю порівняно з Ruby.

Докази

pic

Реалізація на Go

pic

Реалізація на Ruby

Код

Реалізація на Go:

func isPalindrome(x int) bool {  
 if x < 0 {  
 return false // Від'ємні числа не є паліндромами  
 }  
 tmp := x  
 rev := 0  
 for tmp > 0 {  
 rev = rev*10 + tmp%10  
 tmp = tmp / 10  
 }  
 return x == rev  
}

Використання пам'яті: 6.03 MB

Реалізація на Ruby:

def is_palindrome(x)  
 return false if x < 0  
 tmp = x  
 rev = 0  
 while tmp > 0  
 rev = rev * 10 + tmp % 10  
 tmp = tmp / 10  
 end  
 x == rev  
end

Використання пам'яті: 211.55 MB

Аналіз різниці в пам'яті

1. Механізм збору сміття

  • Go має оптимізований збірник сміття (garbage collector (GC)), який ефективно керує виділенням та звільненням пам'яті.
  • Збірник сміття в Ruby, хоча й потужний, має тенденцію тримати об'єкти довше, що призводить до більшого споживання пам'яті.

2. Зберігання змінних та їх представлення

  • Go використовує статично типізовані цілі числа, де int — це фіксований 32-бітний або 64-бітний тип залежно від системи.
  • Ruby, будучи динамічно типізованим, зберігає цілі числа як об'єкти, що означає, що кожне ціле число має додаткові метадані та накладні витрати.

3. Стратегія виділення пам'яті

  • Go ефективно виділяє пам'ять на стеку, що призводить до мінімальних накладних витрат для примітивних типів.
  • Ruby виділяє все на купі, що призводить до більшої фрагментації пам'яті та підвищеного споживання пам'яті.

4. Інтерпретовані проти компільованих мов

  • Go є компільованою мовою, що означає, що керування пам'яттю відбувається під час компіляції, оптимізуючи продуктивність.
  • Ruby є інтерпретованою мовою, що додає додаткові шари для виділення та керування пам'яттю під час виконання.

5. Накладні витрати на об'єкти в Ruby

  • У Ruby навіть цілі числа є об'єктами, що означає наявність додаткових метаданих класу, таблиць методів та накладних витрат на динамічну типізацію.
  • Go розглядає цілі числа як примітивні типи, уникаючи зайвих накладних витрат.

Висновок

Велика різниця в споживанні пам'яті між Go та Ruby є наслідком основних дизайнерських рішень. Go надає пріоритет продуктивності, виділенню пам'яті на стеку та ефективному збору сміття, що робить його набагато більш економним щодо споживання пам'яті. Ruby, завдяки своїй динамічній природі, виділенню пам'яті на купі та об'єктно-орієнтованому підходу, вводить значні накладні витрати.

Якщо ефективність пам'яті є ключовим фактором у вашому проєкті, Go є явно кращим вибором. Однак якщо ви надаєте перевагу продуктивності розробника та виразності над чистою продуктивністю, Ruby залишається відмінним варіантом.

Що ви думаєте? Чи спостерігали ви подібні відмінності у використанні пам'яті між мовами? Поділіться думками в коментарях!

Перекладено з: Go vs Ruby: Why Does Go Use So Much Less Memory?