skip to content
Alvin Lucillo

Basic memory profile

/ 2 min read

Based on the functions from the earlier entries (growing and preallocated batch functions), the commands below create memory profiles and check them. We already know that the preallocated version is much efficiently CPU-wise, as shown by the comparison of ns it took to process each operation.

This block of code create memory profiles, with 100 operations, instructing the tool to record every allocation.

go test -run '^$' \
  -bench '^BenchmarkBuildMessageBatch$/^implementation=growing$' \
  -benchtime=100x \
  -memprofilerate=1 \
  -memprofile=/tmp/codec01-message-batch-growing-memory.pprof
goos: linux
goarch: amd64
pkg: codec01
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkBuildMessageBatch/implementation=growing-12                 100            115569 ns/op         553.78 MB/s      285432 B/op         19 allocs/op
PASS
ok      codec01 0.032s

go test -run '^$' \
  -bench '^BenchmarkBuildMessageBatch$/^implementation=preallocated$' \
  -benchtime=100x \
  -memprofilerate=1 \
  -memprofile=/tmp/codec01-message-batch-preallocated-memory.pprof
goos: linux
goarch: amd64
pkg: codec01
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkBuildMessageBatch/implementation=preallocated-12                    100             28219 ns/op        2267.98 MB/s       65589 B/op          1 allocs/op
PASS
ok      codec01 0.021s

Now, looking at the profiles, specifying -alloc_space for the total bytes over the program’s lifetime, there’s not much it can tell about why the preallocated version is superior in terms of the size of the heap allocations. As we know, larger heap allocations is not good because it affects resources. For example, it would make the garbage collector busy, thus increasing CPU work.

The total allocated heap memory by the “growing” function version is ~28MB and “preallocated” function version ~6MB.

go tool pprof -top -alloc_space \
  /tmp/codec01-message-batch-growing-memory.pprof
File: codec01.test
Build ID: a94b6e5f69aad830296a1e71a08c11623fd119cb
Type: alloc_space
Time: 2026-10-31 21:13:06 CST
Showing nodes accounting for 27869.05kB, 99.54% of 27996.98kB total
Dropped 158 nodes (cum <= 139.98kB)
      flat  flat%   sum%        cum   cum%
27868.75kB 99.54% 99.54% 27868.75kB 99.54%  codec01.BuildMessageBatchGrowing (inline)
    0.30kB 0.0011% 99.54% 27929.69kB 99.76%  testing.(*B).runN
         0     0% 99.54% 27868.86kB 99.54%  codec01.BenchmarkBuildMessageBatch.func1
         0     0% 99.54% 27925.25kB 99.74%  testing.(*B).run1.func1

go tool pprof -top -alloc_space \
  /tmp/codec01-message-batch-preallocated-memory.pprof
File: codec01.test
Build ID: a94b6e5f69aad830296a1e71a08c11623fd119cb
Type: alloc_space
Time: 2026-10-31 21:13:08 CST
Showing nodes accounting for 6425.71kB, 98.52% of 6522.52kB total
Dropped 140 nodes (cum <= 32.61kB)
      flat  flat%   sum%        cum   cum%
    6400kB 98.12% 98.12%     6400kB 98.12%  codec01.BuildMessageBatchPreallocated (inline)
   24.06kB  0.37% 98.49%    53.47kB  0.82%  codec01.BenchmarkBuildMessageBatch
    1.28kB  0.02% 98.51%    47.13kB  0.72%  regexp.compile
    0.30kB 0.0046% 98.51%  6460.02kB 99.04%  testing.(*B).runN
    0.07kB 0.0011% 98.52%    36.20kB  0.55%  testing.(*M).Run
         0     0% 98.52%     6400kB 98.12%  codec01.BenchmarkBuildMessageBatch.func2
         0     0% 98.52%    36.20kB  0.55%  main.main
         0     0% 98.52%    47.13kB  0.72%  regexp.Compile (inline)
         0     0% 98.52%    36.20kB  0.55%  runtime.main
         0     0% 98.52%  6455.58kB 98.97%  testing.(*B).run1.func1
         0     0% 98.52%    34.84kB  0.53%  testing.(*matcher).fullName
         0     0% 98.52%    34.11kB  0.52%  testing.simpleMatch.matches
         0     0% 98.52%    52.59kB  0.81%  testing/internal/testdeps.TestDeps.MatchString