In my code, I need to create a struct to hold two vectors. In terms of speed and memory allocations, would it make a difference if I make it mutable instead of immutable, assuming that there’s no need to make to mutable?
Presumably you are trying to profile it?
Using immutable
s seems to make aliasing analysis slightly easier for the compiler, see some analysis in e.g. https://github.com/JuliaLang/julia/pull/16371#issuecomment-219644197.
I don’t know all the details, but in general I would expect to see a much bigger difference between bits types and non-bits types than immutables vs. mutables. A bits type is a primitive or an immutable struct whose fields are all bits types. You can test that with isbits()
. Notably, bits types can be stack-allocated, so you can construct them at will with little to no speed or allocation penalty. Here’s a simple demo:
julia> mutable struct MyMutable
x::Vector{Int}
end
julia> struct MyImmutable
x::Vector{Int}
end
julia> using StaticArrays: SVector
julia> struct MyBits
x::SVector{2, Int}
end
Vector
is not a bits type, so both MyMutable
and MyImmutable
are not bits types. But StaticArrays.SVector{2, Int}
is a bits type (because it’s immutable and contains only a tuple of two integers), so MyBits
is also a bits type. This has a significant performance impact in code that constructs a lot of objects:
julia> using BenchmarkTools
julia> function f_mutable()
for i in 1:1000
x = MyMutable([rand(Int), rand(Int)])
end
end
f_mutable (generic function with 1 method)
julia> function f_immutable()
for i in 1:1000
x = MyImmutable([rand(Int), rand(Int)])
end
end
f_immutable (generic function with 1 method)
julia> function f_bits()
for i in 1:1000
x = MyBits(SVector(rand(Int), rand(Int)))
end
end
f_bits (generic function with 1 method)
julia> @btime f_mutable()
44.277 μs (3000 allocations: 125.00 KiB)
julia> @btime f_immutable()
44.220 μs (3000 allocations: 125.00 KiB)
julia> @btime f_bits()
13.201 μs (0 allocations: 0 bytes)
True but the question was specifically about: