Where exactly memory copies happen in Julia code?

I have a simple question about memory management in Julia code. Coming from a C++ background with all that rvalue reference madness and move semantics stuff, I got my brain damaged, and I am having a hard time trying to reason about memory management again in other languages.

Consider the following cases:

Case 1

I have an immutable struct that requires a decent amount of memory (e.g. mesh with vertices, edges, triangles). By using composition, I define other concepts (e.g. path):

abstract type AbstractMesh end

struct Mesh <: AbstractMesh
vertices::Vector{...}
edges::Vector{...}
triangles::Vector{...}
end

struct Path{M<:AbstractMesh}
m::M
other_attributes
end

# define behavior of Path using the mesh inside
coords(p::Path, location) = somefunc(p.m, location)

Questions

  1. Will the data stored in the Mesh object be copied to the Path object? If yes, how to avoid this?
  2. How the keyword mutable would affect the copying in this case? Consider two cases: a) adding mutable to the Mesh type, and b) adding mutable to the Path type.

Case 2

I have a big container object (e.g. Container) that I will be passing to functions:

struct Container
data::HugeDataVector
end

Questions

  1. When will a call f(c) where c is a Container create a copy of the object inside of the body of f? How the mutable keyword plays here?
  2. I have heard that immutable objects are always copied around, is that correct? If yes, how do you enforce “const semantics” to a type without killing performance?
1 Like

Things are never copied implicitly. The mutable keyword has nothing to do with this, it only says whether you are allowed to modify (rebind) the fields of the struct (which might determine if it will be stored on the stack or the heap).

The semantics are that they are always copied. If the struct is big enough the compiler can just pass them by reference. Since they are immutable, you will never know the difference.

2 Likes

Thank you @kristoffer.carlsson, so objects are never copied in the examples above? Maybe if you could address the questions I raised, it would be even clearer…

When you say that immutable types have copy semantics, you mean that when we try to modify the object, we will get a copy, but not otherwise? That sounds like an awesome feature.

The semantics are that no objects, immutable or mutable, are ever copied.
Immutables can be copied if necessary.

2 Likes

No.

No, you can’t modify an immutable (see the correction to my statement above though).

1 Like

All values in julia has the same semantics as pointers or lvalue reference in C, with the additional semantics that you are not allowed to mutate some of the references. (similar to a strict version of const)

Undefined and you are not able to notice the difference.

mutable makes it invalid to copy in general (the compiler can still copy if it proved that the object doesn’t escape and doing that increases performance).

Semantically, never. When the compiler thinks it’s valid and beneficial to do so in reality. mutable makes it harder to proof the validity in general, but a mutable on the Container type has no effect at all.

No.

Report a performance bug if the compiler heuristic is sub-optimal.

Also, do note that copy here corresponds to copy of POD in C++. The compiler never, ever, call copy.

2 Likes

Thank you all, it is really to nice to see that no copies are being made at all, and that this machinery is hidden from the user to some extent. Awesome design :+1: