mxs.sbrk.org ยป blog | home | projects

How to get statistics about memory in Golang

I recently played with golang and was a bit surprised about the memory usage of a program displayed by top. Let's see how to use some reflective tools from the runtime package to retrieve information about the running program. We will write data to a file, and then process it with gnuplot to display a graph. We'll need the following packages:

So the first step is to import them:

import (
    "os"
    "fmt"
    "runtime"
    "time"
)

We need a function to create the file at startup :

const MEMLOG_PATH = "memory.log"     // path to log memory statistics
var memlog *os.File = nil

func InitMemLog() (bool) {
    var err os.Error
    memlog, err = os.Open(MEMLOG_PATH, os.O_WRONLY | os.O_CREAT, 0666)
    if err != nil {
        fmt.Printf("Unable to open %s
", MEMLOG_PATH)
        return false
    }
    return true
}

Then, we need to find a place in the program which is repeatedly executed, so as to trigger the following function that writes to the log file:

func MemLog() {
    if memlog != nil {
        t := time.LocalTime()
        if t != nil {
            s := runtime.MemStats
            memlog.WriteString(
                fmt.Sprintf("%d %d %d
", t.Seconds(), s.Alloc, s.Sys))
        }
    }
}

This will write to the log file something as follow:

# timestamp     in use memory   allocated memory
1294926363      4433792         11118840
1294926399      9375280         17537272
1294926461      11561584        24692984
1294926539      6964664         27924728
1294926560      9147696         27924728
1294926659      6689736         27924728

The difference between in use memory and allocated memory is that the current garbage collector doesn't release memory at all, and keeps unused memory for a later use. That's why the amount of memory used by your program may be very surprising when looking at what's being reported by top.

Finally, let's create a plot script to display our data in a nice way :

set xlabel "time"
set xdata time
set format x "%H:%M"
set timefmt "%s"
set format y "%2.0f"
set mxtics 10
set ylabel "bytes"
set autoscale
plot  "memory.log" using 1:2 title 'In use memory' with lines, \
      "memory.log" using 1:3 title 'System memory' with lines

The result can be seen by running the following:

$ gnuplot -p mem.plot

Which will display something like:

gnuplot


Generated on Sun Apr 15 13:15:49 UTC 2012 by gromit.sh