Code

Watch the capacity grow

Create stats.go (see the panel). It adds two commands: algo load and algo stats -growth.

stats -growth appends one item at a time and prints the slice header every time cap changes. Each of those lines is one fresh array and one full copy.

How a Go slice actually grows

$ algo stats -growth -n 1000
  append      len      cap items copied
       1        1        1            0
       2        2        2            1
       3        3        4            2
       5        5        8            4
       9        9       18            8
      19       19       36           18
      37       37       73           36
      74       74      146           73
     147      147      292          146
     293      293      585          292
     586      586     1024          585

1000 appends, 11 reallocations, 1165 items copied in total
average copies per append: 1.165

The textbook says "the capacity doubles". Look at the numbers: 1, 2, 4, 8, 18, 36, 73, 146, 292, 585, 1024.

Eighteen, not sixteen. Seventy-three, not seventy-two. One thousand and twenty-four, not one thousand one hundred and seventy.

Go doubles only at the start. Past a few hundred elements it grows by roughly 1.25×, and then rounds the result up to an allocator size class. The textbook rule is an approximation; the real behaviour is the one you just measured.

What "amortized" actually costs

One number answers the whole question. Grow n and watch the last line:

n reallocations items copied average per append
1,000 11 1,165 1.165
10,000 19 35,540 3.554
100,000 29 456,253 4.563
1,000,000 39 4,467,696 4.468

Two things are visible immediately.

The average stops growing. 100,000 and 1,000,000 give almost the same answer — about 4.5 copies per append. That is amortized O(1): the average is constant. If append were really O(n) you would see about 500,000 at a million, not 4.5.

But the constant is not 1. It is ~4.5, and that follows directly from the 1.25 growth factor: if capacity grows by a factor g, each element is copied about 1/(g−1) times on average, and 1/(1.25−1) = 4.

"Amortized O(1)" does not mean free. It means constant. The constant is something you can measure — and you just did.

The reallocation count grows logarithmically: 11, 19, 29, 39 — about ten more for each factor of ten in n. A thousand times the data costs twenty extra reallocations, not a thousand.