Last active
March 4, 2023 21:26
-
-
Save leonid-shevtsov/4bb9383ae3f491afa40319267056581f to your computer and use it in GitHub Desktop.
Memory usage: Ruby vs Go vs JavaScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"log" | |
"os" | |
"os/exec" | |
"runtime" | |
"strconv" | |
"strings" | |
) | |
func getmem() int { | |
cmd := exec.Command("ps", "-o", "rss", fmt.Sprintf("%d", os.Getpid())) | |
output, err := cmd.Output() | |
if err != nil { | |
log.Fatal(err) | |
} | |
rssStr := strings.TrimSpace(strings.Split(string(output), "\n")[1]) | |
rss, err := strconv.Atoi(rssStr) | |
if err != nil { | |
log.Fatal(err) | |
} | |
return rss | |
} | |
func measure[ItemType any](title string, count int, code func(int) ItemType) []ItemType { | |
runtime.GC() | |
startmem := getmem() | |
ary := make([]ItemType, count) | |
for i := 0; i < count; i++ { | |
ary[i] = code(i) | |
} | |
runtime.GC() | |
endmem := getmem() | |
fmt.Printf("%d %s: %d KB; %db per item\n", count, title, endmem-startmem, (endmem-startmem)*1024/count) | |
return ary | |
} | |
type StructType struct { | |
foo int | |
bar int | |
baz int | |
} | |
func main() { | |
measure("int", 10000000, func(i int) int { | |
return i | |
}) | |
// measure("str", 10000000, func(i int) string { | |
// return fmt.Sprintf("%10d", i) | |
// }) | |
// measure("const str", 10000000, func(i int) string { | |
// return "xxxxxxxxxx" | |
// }) | |
// measure("const str generated", 10000000, func(i int) string { | |
// return strings.Repeat("x", 10) | |
// }) | |
// measure("struct", 10000000, func(i int) StructType { | |
// return StructType{i, i + 1, i + 2} | |
// }) | |
// measure("struct ptr", 10000000, func(i int) *StructType { | |
// return &StructType{i, i + 1, i + 2} | |
// }) | |
// measure("map", 10000000, func(i int) map[string]int { | |
// return map[string]int{"foo": i, "bar": i + 1, "baz": i + 2} | |
// }) | |
// measure("interface", 10000000, func(i int) interface{} { | |
// return StructType{i, i + 1, i + 2} | |
// }) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// nodejs --expose-gc measure_js.js | |
const { memoryUsage } = require("process"); | |
function measureMemory(title, count, gen) { | |
global.gc(); | |
const startmem = memoryUsage.rss(); | |
let result = new Array(count); | |
for (let i = 0; i < count; i++) { | |
result[i] = gen(i); | |
} | |
global.gc(); | |
const endmem = memoryUsage.rss(); | |
console.log( | |
`${count} ${title}: ${(endmem - startmem) / 1024} KB; ${Math.round( | |
(endmem - startmem) / count | |
)}b per item` | |
); | |
return result; | |
} | |
class CustomClass { | |
constructor(i) { | |
this.foo = i; | |
this.bar = i + 1; | |
this.baz = i + 2; | |
} | |
} | |
// measureMemory("int", 10000000, (i) => i); | |
// measureMemory("float", 10000000, (i) => 1.0 / i); | |
// measureMemory("str", 10000000, (i) => i.toString().padStart(10)); | |
// measureMemory("str const", 10000000, (i) => "xxxxxxxxxx"); | |
measureMemory("ad-hoc obj", 10000000, (i) => ({ | |
foo: i, | |
// bar: i + 1, | |
// baz: i + 2, | |
// abc: i + 2, | |
// sdf: i + 2, | |
// asa: i + 2, | |
// per: i + 2, | |
// sff: i + 2, | |
// sss: i + 2, | |
})); | |
// measureMemory("custom class", 10000000, (i) => new CustomClass(i)); | |
// 1, 47 | |
// 2,54 | |
// 3, 62 | |
// 4,70 | |
// 5, 78 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def getmem | |
`ps -o rss #{Process.pid}`.lines.last.strip.to_i | |
end | |
def measure_memory(title, count, &block) | |
GC.start | |
startmem = getmem | |
result = Array.new(count, &block) | |
GC.start | |
endmem = getmem | |
puts "#{count} #{title}: #{endmem - startmem} KB; #{(endmem - startmem)*1024/count}b per item" | |
result | |
end | |
StructClass = Struct.new(:foo,:bar,:baz) | |
class CustomClass | |
attr_accessor :foo, :bar, :baz | |
def initialize(foo, bar, baz) | |
@foo, @bar, @baz = foo, bar, baz | |
end | |
end | |
measure_memory("int array", 100_000_000) { |i| i } | |
# measure_memory("str_array 10M") do | |
# Array.new(10_000_000) { |i| format('%10d', i) } | |
# end | |
# measure_memory("str_array_const 10M") do | |
# Array.new(10_000_000) { 'xxxxxxxxxx' } | |
# end | |
# measure_memory("symbol_array 10M") do | |
# Array.new(10_000_000) { :xxxxxxxxxx } | |
# end | |
# measure_memory("struct array", 10_000_000) { |i| StructClass.new(i, i+1, i+2) } | |
# measure_memory("class", 10_000_000) { |i| CustomClass.new(i, i+1, i+2) } | |
# measure_memory("hash ", 10_000_000) { |i| {foo: i, bar: i+1, baz: i+2} } | |
# measure_memory("str hash ", 10_000_000) { |i| {"foo" => i, "bar" => i+1, "baz" => i+2} } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment