This is because Profile.Allocs.@profile returns the actual object size and @allocated returns the size it occupies in memory (Pool size)
Detailed technical answer, take the following input:
julia> g(1)
4 allocs: 128 bytes
4 allocs: 112 bytes
julia> g(2)
4 allocs: 160 bytes
4 allocs: 128 bytes
julia> g(3)
4 allocs: 160 bytes
4 allocs: 144 bytes
Objects have to fit in a specific “pool” in memory, this is why @allocated reports the same memory for for g(2) and g(3) (160 bytes) as the result still fits in the same pool.
I also used CodeGlass to find out what was being allocated. It found:
In REPL function f(n):
Array{Int64,1} (always 32 bytes)
Int64[] (8*n bytes + 16 bytes for array header)
In arraymath.jl:21 function *(A::Int64, B::Array{Int64, 1})::Array{Int64, 1}
Array{ Int64,1} (always 32 bytes)
Int64[] (8*n bytes + 16 bytes for array header)
Julia uses the the following pool sizes that are relevant to this question (julia_internal.h:436)
// 16 pools at 8-byte spacing
// the 8-byte aligned pools are only used for Strings
16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136,
Since it is not a string, it must fit the Int64 bodies into 16 bytes aligned pools, so not in the 24 bytes pool but in the 32 bytes, so for example:
g(1) Allocations:
1x Array{Int64,1} = 32 bytes = 32 bytes in pool
1x Array{Int64,1} = 32 bytes = 32 bytes in pool
1x Int64[] = 8*1+16 = 24 bytes = 32 bytes in pool
1x Int64[] = 8*1+16 = 24 bytes = 32 bytes in pool
Total actual object size: 112 bytes (Reported by Profile.Allocs.@profile)
Total size in pool : 128 bytes (Reported by @allocated)
I hope this was helpful 