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