Clear variables in caller workspace

Hi all,

I want to utilize memory usage in Julia. Before I do some heavy computations, I want to clear some big matrices to optimize the memory usage in my code.

For example, I have two big matrices, A and B. In the function combine_A_B_and_compute, I input A, and B, and combine them to matrix K do some computations. Since A and B are big matrices, after building matrix K, I want to clear A and B (set them to be nothing) inside the function and in the caller workspace.

In Matlab, I can do so by clear A B; evalin(‘caller’, [‘clear A B’]);

In Julia, if I use

function combine_A_B_and_compute(A, B)
K = cat(A,B,dims=1)
A = nothing;
B = nothing;
GC.gc()
……
end

It does not clear A and B in the caller workspace.

The way I have is to define a mutual structure Matrices and making A and B be its fields:

mutable struct Matrices
A::Union{Matrix, Nothing}
B::Union{Matrix, Nothing}
Matrices()=new()
end

Then by setting the fields in mutual struct Matrices to nothing, I can clear A and B in the caller workspace.

function combine_A_B_and_calculate!(X::Matrices)
K = cat(X.A,X.B,dims=1)
X.A = nothing;
X.B = nothing;
GC.gc()
……
end

However, this way is not very intuitive.

Is there a better way to clear variables in the caller workspace in Julia? Thanks!

There is no way to clear variables in the caller workspace. Such concept does not exist. When you call a function all your variables are either global or from your local context (i.e., the function), what you did is to create a mutable object keeping the only references to other objects in the memory, and overwriting the references inside the function, effectively losing the only reference which you did have from them, and allowing them to be garbage collected.

What you can do is:

  1. What you already did.
  2. Do not keep any references on the caller, instead create the objects at the function call (i.e., f(Matrix(...), Matrix(...))) so the code does not keep any references in the caller scope.

To add another option, it is typically a good idea to put performance critical code inside a function. In this case, you can write

function combine_A_B_and_compute(a, b)
    k = cat(a, b, dims=1)
    compute(k)
end

function main()
    a = rand(10_000, 10_000)
    b = rand(10_000, 10_000)
    combine_A_B_and_compute(a, b)
end

main()

which will allow the garbage collector to automatically free the memory used by a and b as soon as control flow passes to compute. This achieves the same result as @Henrique_Becker’s option 2.

3 Likes