简体   繁体   English

Rust Global.dealloc vs ptr::drop_in_place vs ManuallyDrop

[英]Rust Global.dealloc vs ptr::drop_in_place vs ManuallyDrop

I'm relatively new to Rust.我对 Rust 比较陌生。 I was working on some lock-free algorithms, and started playing around with manually managing memory, something similar to C++ new/delete.我正在研究一些无锁算法,并开始尝试手动管理 memory,类似于 C++ new/delete。 I noticed a couple different ways that do this throughout the standard library components, but I want to really understand the differences and use cases of each.我注意到在整个标准库组件中有几种不同的方法可以做到这一点,但我想真正了解每种方法的差异和用例。 Here's what it seems like to me:这就是我的感觉:

ManuallyDrop<Box<T>> will prevent Box's destructor from running. ManuallyDrop<Box<T>>将阻止 Box 的析构函数运行。 I can save a raw pointer to the ManuallyDrop element, and have the actual element go out of scope (what would normally be dropped in Rust) without being dropped.我可以保存一个指向ManuallyDrop元素的原始指针,并让实际元素 go 脱离 scope (通常会在 Rust 中删除)而不被删除。 I can later call ManuallyDrop::drop(&mut *ptr) to drop this value manually.我稍后可以调用ManuallyDrop::drop(&mut *ptr)手动删除该值。

I can also dereference the ManuallyDrop<Box<T>> element, save a raw pointer to just the Box<T> , and later call std::ptr::drop_in_place(box_ptr) .我还可以取消引用ManuallyDrop<Box<T>>元素,将原始指针保存到Box<T> ,然后调用std::ptr::drop_in_place(box_ptr) This is supposed to destroy the Box itself and drop the heap-allocated T .这应该破坏Box本身并丢弃堆分配的T

Looking at the ManuallyDrop::drop implementation, it looks those are literally doing the exact same thing.查看ManuallyDrop::drop实现,看起来它们实际上在做完全相同的事情。 Since ManuallyDrop is zero cost and just stores a value in it's struct, is there any difference in the above two approaches?由于ManuallyDrop是零成本并且只是在其结构中存储一个值,因此上述两种方法有什么区别吗?

I can also call std::alloc::Global.dealloc(...) , which looks like it will deallocate the memory block without calling drop.我也可以调用std::alloc::Global.dealloc(...) ,看起来它会在不调用 drop 的情况下释放 memory 块。 So if I call this on a pointer to Box<T> , it'll deallocate the heap pointer, but won't call drop , so T will still be lying around on the heap.因此,如果我在指向Box<T>的指针上调用它,它将释放堆指针,但不会调用drop ,因此T仍将躺在堆上。 I could call it on a pointer to T itself, which will remove T .我可以在指向T本身的指针上调用它,这将删除T

From exploring the standard library, it looks like Global.dealloc gets called in the raw_vec implementation to actually remove the heap-allocated array that Vec points to.通过探索标准库,看起来Global.deallocraw_vec实现中被调用以实际删除Vec指向的堆分配数组。 This makes sense, since it's literally trying to remove a block of memory.这是有道理的,因为它实际上是在尝试删除 memory 块。

Rc has a drop implementation that looks roughly like this: Rc有一个 drop 实现,大致如下所示:

// destroy the contained object
ptr::drop_in_place(self.ptr.as_mut());

// remove the implicit "strong weak" pointer now that we've
// destroyed the contents.
self.dec_weak();

if self.weak() == 0 {
    Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
}

I don't really understand why it needs both the dealloc and the drop_in_place .我真的不明白为什么它需要deallocdrop_in_place What does the dealloc add that the drop_in_place doesn't do? dealloc添加了drop_in_place没有做什么?

Also, if I just save a raw pointer to a heap-allocated value by doing something like Box::new(5).into_raw() , does my pointer now control that memory allocation.此外,如果我只是通过执行类似Box::new(5).into_raw()类的操作来保存指向堆分配值的原始指针,那么我的指针现在是否控制 memory 分配。 As in, will it remain alive until I explicitly call ptr::drop_in_place() ?如,在我明确调用ptr::drop_in_place()之前它会保持活动状态吗?

Finally, when I was playing with all this, I ran into a strange issue.最后,当我在玩这一切时,我遇到了一个奇怪的问题。 After running ManuallyDrop::drop or ptr::drop_in_place on my raw pointer, I then tried running println!在我的原始指针上运行ManuallyDrop::dropptr::drop_in_place之后,我尝试运行println! on the pointer's dereferenced value.在指针的取消引用值上。 Sometimes I get a scary heap error and my test fails, which is what I would expect.有时我得到一个可怕的堆错误,我的测试失败了,这是我所期望的。 Other times, it just prints the same value, as if no drops happened.其他时候,它只打印相同的值,就好像没有发生任何下降一样。 I also tried running ManuallyDrop::drop multiple times on the exact same value, and same thing.我还尝试在完全相同的值和相同的东西上多次运行ManuallyDrop::drop Sometimes a heap error, sometimes totally fine, and the same value prints out.有时是堆错误,有时完全没问题,并且打印出相同的值。

What is happening here?这里发生了什么?

If you come from C++, you can think of drop_in_place as calling the destructor manually, and dealloc as calling old C free .如果你来自 C++,你可以认为drop_in_place是手动调用析构函数,而dealloc是调用旧的 C free

They serve different purposes:它们有不同的用途:

  • drop_in_place just calls Drop::drop , that releases the resources held by your type. drop_in_place只是调用Drop::drop ,它会释放你的类型持有的资源。
  • dealloc frees the memory pointed to by a pointer, previously allocated with alloc . dealloc释放了由指针指向的 memory,之前使用alloc分配。

You seem to think that drop_in_place also frees the memory, but that is not the case.您似乎认为drop_in_place也释放了 memory,但事实并非如此。 I think your confusion arises because Box<T> contains a dynamically allocated object, so its Box::drop implementation does release the memory used by that object, after calling its drop_in_place , of course.我认为你的困惑是因为Box<T>包含一个动态分配的 object,所以它的Box::drop实现在调用它的drop_in_place之后确实释放了 object 使用的 memory。

That is what you see in the Rc implementation, first it calls the drop_in_place (destructor) of the inner object, then it releases the memory.这就是你在Rc实现中看到的,首先它调用内部 object 的drop_in_place (析构函数),然后释放 memory。

About what happens if you call drop_in_place several times in a row... well, the function is unsafe for a reason: you most likely get Uundefined Behavior .如果您连续多次调用drop_in_place会发生什么......好吧,function 不安全是有原因的:您很可能会得到Uundefined Behavior From the docs:从文档:

...if T is not Copy , using the pointed-to value after calling drop_in_place can cause undefined behavior. ...如果 T 不是Copy ,则在调用drop_in_place后使用指向的值可能会导致未定义的行为。

Note the can cause .注意can cause I think it is perfectly possible to write a type that allows calling drop several times, but it doesn't sound like such a good idea.我认为编写一个允许多次调用drop的类型是完全可能的,但这听起来不是一个好主意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM