According to https://doc.rust-lang.org/stable/rust-by-example/std/box.html,
All values in Rust are stack allocated by default. Values can be boxed
(allocated on the heap) by creating a Box. A box is a smart pointer
to a heap allocated value of type T. When a box goes out of scope, its
destructor is called, the inner object is destroyed, and the memory on
the heap is freed.
So if I have a std::vec::Vec<MyStruct> and I add a lot of structs, does this mean that the structs are stack allocated? How can this be possible? I can only have a collection of things if they're on the heap. Things on the stack are made in compile time, since I understand.
A Box is one way of allocating on the heap, but it is not the only way. Other data structures, including Vec, store their data on the heap. So in this case, as you create each instance of MyStruct initially it will be on the stack, but as soon as you push it onto the Vec, it will be moved to the heap. At least, that's conceptually how it works; depending on the specific situation and the compiler optimization settings, Rust may be able to avoid physically writing to the stack, instead writing directly to the heap.
Related
I have read that Rust's compiler "inserts" memory management code during compile time, and this sounds kind of like "compile-time garbage collection".
What is the difference between these two ideas?
I've seen What does Rust have instead of a garbage collector? but that is about runtime garbage collection, not compile-time.
Compile-time garbage collection is commonly defined as follows:
A complementary form of automatic memory management is compile-time memory management (CTGC), where the decisions for memory management are taken at compile-time instead of at run-time. The compiler determines the life-time of the variables that are created during the execution of the program, and thus also the memory that will be associated with these variables. Whenever the compiler can guarantee that a variable, or more precisely, parts of the memory resources that this variable points to at run-time, will never ever be accessed beyond a certain program instruction, then the compiler can add instructions to deallocate these resources at that particular instruction without compromising the correctness of the resulting code.
(From Compile-Time Garbage Collection for the Declarative Language Mercury by Nancy Mazur)
Rust handles memory by using a concept of ownership and borrow checking. Ownership and move semantics describe which variable owns a value. Borrowing describes which references are allowed to access a value. These two concepts allow the compiler to "drop" the value when it is no longer accessible, causing the program to call the dtop method from the Drop trait).
However, the compiler itself doesn't handle dynamically allocated memory at all. It only handles drop checking (figuring out when to call drop) and inserting the .drop() calls. The drop implementation is responsible for determining what happens at this point, whether that is deallocating some dynamic memory (which is what Box's drop does, for example), or doing anything else. The compiler therefore never really enforces garbage collection, and it doesn't enforce deallocating unused memory. So we can't claim that Rust implements compile-time garbage collection, even if what Rust has is very reminiscent of it.
Is there any option to use shared memory for Vec<f64> in Rust?
Processes in my program swap two or more values in a Vec<f64> and I need the memory to be shared between processes.
There is no way to safely create a Vec backed by shared memory. There are two reasons this is true:
A Vec owns its memory and will reallocate it when grown or free it when dropped. Unsafely creating a Vec pointing to mmapped memory will corrupt the heap when the Vec reallocates or goes out of scope.
A Vec has exclusive access to its memory, like a &mut reference. The compiler is free to omit and reorder reads and writes based on the assumption that nothing else is using the memory. If this assumption is broken, the behavior is undefined. To relax this assumption, your data type needs to be something based on UnsafeCell.
Vec is the wrong pointer for this job. Try &[UnsafeCell<f64>], or maybe &[AtomicU64] (with conversions using from_bits and to_bits), since there isn't an AtomicF64 in the standard library.
When searching for an answer, I found this question, however there is no mention of static lifetime objects. Can the method mentioned in this answer (calling drop() on the object) be used for static lifetime objects?
I was imagining a situation like a linked list. You need to keep nodes of the list around for (potentially) the entire lifetime of the program, however you also may remove items from the list. It seems wasteful to leave them in memory for the entire execution of the program.
Thanks!
No. The very point of a static is that it's static: It has a fixed address in memory and can't be moved from there. As a consequence, everybody is free to have a reference to that object, because it's guaranteed to be there as long as the program is executing. That's why you only get to use a static in the form of a &'static-reference and can never claim ownership.
Besides, doing this for the purpose of memory conservation is pointless: The object is baked into the executable and mapped to memory on access. All that could happen is for the OS to relinquish the memory mapping. Yet, since the memory is never allocated from the heap in the first place, there is no saving to be had.
The only thing you could do is to replace the object using unsafe mutable access. This is both dangerous (because the compiler is free to assume that the object does not in fact change) and pointless, due to the fact that the memory can't be freed, as it's part of the executable's memory mapping.
It seems like Box.clone() copies the heap memory. As I know, Box will get destructed after it gets out of its scope, as well as the memory area it is pointing to.
So I'd like to ask a way to create more than one Box object pointing to the same memory area.
By definition, you shall not.
Box is explicitly created with the assumption that it is the sole owner of the object inside.
When multiple owners are required, you can use instead Rc and Arc, those are reference-counted owners and the object will only be dropped when the last owner is destroyed.
Note, however, that they are not without downsides:
the contained object cannot be mutated without runtime checks; if mutation is needed this requires using Cell, RefCell or some Mutex for example,
it is possible to accidentally form cycles of objects, and since Rust has no Garbage Collector such cycles will be leaked.
Basically I have a heap-allocated struct Box<State>. I have multiple Value structs that need to have an immutable reference to this heap-allocated struct.
What kind of attribute can I use inside of Value for this reference? Using Rc<Box<State>> does not work because I need Value to implement Copy and State does not implement Copy. When it needs to copy itself, I just want to copy the pointer to that heap-allocated State.
What you're asking for is basically impossible. If you have many pointers to the heap allocation floating around, you need to somehow keep track of these pointers to be able to deallocate once all these pointers are destroyed. However, that requires doing something whenever one of the pointer is duplicated, and/or doing something when the pointers are destroyed.
Well, that's not quite true, there are two ways around this:
Don't deallocate, i.e., leak memory
Have a garbage collector periodically going through all memory that might contain pointers to the allocation.
But the first is impractical in most contexts (and quite dirty even when you can afford it), and the second has other costs and far-reaching consequences and is not really well supported in current Rust anyway.
The only sane thing is to drop the Copy requirement. Perhaps you're confusing Copy with Clone? The primary difference between the two is that you have to call clone() explicitly while Copy works implicitly. Rc<anything> is Clone and cloning the reference counted pointer will only increment the refcount, not clone the thing behind the pointer. (And in this case you almost certainly can and should get rid of the Box, since Rc<T> already allocates the T on the heap, so the Box is just a pointless additional indirection.)