Understanding allocations reported by --track-allocation (solved)

I’m trying to understand the output of --track-allocation=user on this very straightforward snippet:

mutable struct S
    n
    positions
end

function S(n)
    return S(n, zeros(Float32,n))
end

function (@main)(args)
    N = 100
    s = S(N)

    for i in 1:N
        s.positions[i] += 1f0
    end
end

Does the s.positions[i] += 1f0 really allocate 32 bytes per execution? Or is this something that the allocation tracking is not reporting correctly?

        - mutable struct S
        -     n
        -     positions
        - end
        - 
        - function S(n)
        -     return S(n, zeros(Float32,n))
        - end
        - 
        - function (@main)(args)
        -     N = 100
      480     s = S(N)
        - 
        0     for i in 1:N
     3200         s.positions[i] += 1f0
        0     end
        - end
Julia Version 1.12.3
Commit 966d0af0fdf (2025-12-15 11:20 UTC)
Build Info:
  Official https://julialang.org release
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 8 × Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz
  WORD_SIZE: 64
  LLVM: libLLVM-18.1.7 (ORCJIT, skylake)
  GC: Built with stock GC
Threads: 8 default, 1 interactive, 8 GC (on 8 virtual cores)
Environment:
  JULIA_PKG_USE_CLI_GIT = true
  JULIA_NUM_THREADS = auto

Edit: ah, it’s the mutability of the struct causing it

        - struct S
        -     n
        -     positions
        - end
        - 
        - function S(n)
        -     return S(n, zeros(Float32,n))
        - end
        - 
        - function (@main)(args)
        -     N = 100
      480     s = S(N)
        - 
        0     for i in 1:N
        0         s.positions[i] += 1f0
        0     end
        - end

As a side note, try to always type the fields of a struct, otherwise you will get Any fields, which can lead to poor performance. You can add type parameters to let the compiler figure out the types for you:

struct S{N,P}
  n::N
  positions::P
end