Is it possible to manually manage the memory without having to use C Standard Library?

If I want maximum performance for a program written in Julia, one of my options would be manually managing the memory with help of Julia C Standard Library.

But is it possible to do that in another way? Has Julia facilities for manually manage the memory?

In summary no. Ideally if you want maximum performance you don’t want to allocate in your hot path at all.

3 Likes

And if you’re not allocating in the path then you can just use preallocated Julia memory, Array and such

1 Like

Depends what you mean by “manage”.

Do you mean pre-allocate memory and re-use it? Sure, Julia provides lots of in-place operations that act on existing arrays and other data structures. You can even allocate storage for one type and re-use it for another type using reinterpret.

Do you mean working avoiding garbage collection entirely and manually free-ing memory as needed? Yes, you can allocate your own memory by malloc and use raw pointers (or unsafe_wrap to treat them as arrays/etcetera), but it obviously takes a lot more care. Usually this is not worth it except to interact with external non-Julia libraries.

Do you mean swapping in a custom garbage-collection algorithm for standard Julia objects? Not really, without recompiling Julia itself and doing a lot of low-level hacking. Of course, you can turn GC off completely with GC.enable(false), and manually invoke it with GC.gc().

4 Likes

I read on an article that D, Nim and Rust can be as fast as C if managing the memory manually, I don’t believe that managing the memory manually should be restricted to interacting with non-Julia libraries only.

I didn’t know that GC can be disabled, good to know.

That article was certainly mistaken, as there’s no need for manually managing memory (i.e., calling malloc and free by hand) in Rust.

While disabling GC is an option, writing your code in a way that doesn’t require GC to run much (if at all) by reducing allocations in the first place, is as good as managing memory manually with malloc et al.

1 Like

Here is the article: completely-unscientific-benchmarks/README.md at master · frol/completely-unscientific-benchmarks · GitHub

/\ “Nim, D, and Rust can go as fast as C/C++ can when you switch to “unsafe” manual memory management.”

While disabling GC is an option, writing your code in a way that doesn’t require GC to run much (if at all) by reducing allocations in the first place, is as good as managing memory manually with malloc et al.

Is that I want to do in the future (I’m still studying programming).

I had never heard of that benchmark so I went and looked and it describes itself as being a benchmark primarily for memory management intensive operations

For the most part that’s just not true of most real world problems that you would choose to use Julia for so I don’t think it’s particularly relevant to decision making

It’s definitely the case that memory management can slow down your programs but there are many many ways to account for that within Julia without resorting to malloc

I am oldstyle, I prefer to manage the memory manually.

The thing that made me choose Julia is String macros: Five (More) Reasons to Check Out Julia

Did you remember when you was a very young child and you played with play dough? I can do the same with Julia macros and its memory management facilities.

There are many ways to do this in Julia without resorting to malloc

It’s usually a mistake to avoid allocations (they are not slow), or to use Libc.malloc directly.

When you allocate indirectly the same Libc.malloc is used (and same or better speed). For real-time, you want to avoid GC triggered, by avoiding allocations in parts of your program (a main loop). Even if you want to manage your own memory call Libc.malloc, there are packages you may want to use rethar than Julia’s standard library API directly. See e.g. StaticTools.jl.

Avoiding Libc.malloc entirely, directly or indirectly is problematic. Then you have no heap.

I theory you can get memory straight from the kernel (e.g. Linux’s or Windows’s etc), but your program wouldn’t be portable that way. You really want to use malloc in libc at least indirectly for portability.

There are alternative malloc than in the default libc, e.g. mimalloc and there’s a PR to make it work in Julia. It’s a good replacement. There are also alternative libc available, see musl Julia, and Cosmobilitan is interesting but not yet supported…

There are many ways to do this in Julia without resorting to malloc

Yes, I’m going to study them all.

In GitHub - mkitti/ArrayAllocators.jl: Allocate arrays with malloc, calloc, or on NUMA nodes I put together some methods of allocating and wrapping them in arrays.

For example on Windows, I wrap VirtualAllocEx: ArrayAllocators.jl/Windows.jl at 455341fcd3ac20865d454b9cbfdc0841bf8b333f · mkitti/ArrayAllocators.jl · GitHub

On Linux, I wrap posixmemalign:

I usually add a finalizer to these so automatically free the memory, but you do need to do that if you wish to manually free it.

You mentioned strings. I’ve been working on static memory allocation in InlineStrings.jl and StaticStrings.jl including implement string macros.

1 Like

mkitti

Thanks, I bookmarked all of them.

Data structures often allocate without user control, so this may be hard to achieve in many cases. For instance, in Julia I cannot fill a Dict using a preallocated backing buffer; other languages make this easier.

Another example is that views can allocate without user approval and hurt performance [RFC/ANN] Restacker.jl: A workaround for the heap-allocated-immutable problem?.

SimpleChains.jl is a library that manually manages its memory internally via reinterpreting and bumping pointers.
It will reuse the same memory between calls to avoid allocations.
Rather than use malloc, it just allocates a regular Julia Vector{UInt8} and gets the pointer.

2 Likes