简体   繁体   English

我可以使用 Box::from_raw 从 Vec::into_boxed_slice 中释放 memory 吗?

[英]Can I free memory from Vec::into_boxed_slice using Box::from_raw?

I saw the following code for returning a byte array to C:看到以下代码将字节数组返回到 C:

#[repr(C)]
struct Buffer {
    data: *mut u8,
    len: usize,
}

extern "C" fn generate_data() -> Buffer {
    let mut buf = vec![0; 512].into_boxed_slice();
    let data = buf.as_mut_ptr();
    let len = buf.len();
    std::mem::forget(buf);
    Buffer { data, len }
}

extern "C" fn free_buf(buf: Buffer) {
    let s = unsafe { std::slice::from_raw_parts_mut(buf.data, buf.len) };
    let s = s.as_mut_ptr();
    unsafe {
        Box::from_raw(s);
    }
}

I notice that the free_buf function takes a Buffer , instead of a *mut u8 .我注意到free_buf function 采用Buffer ,而不是*mut u8 Is this intentional?这是故意的吗?

Can the free_buf function be reduced to:可以将free_buf function 简化为:

unsafe extern "C" fn free_buf(ptr: *mut u8) {
    Box::from_raw(ptr);
}

You are correct to note that the C runtime free function takes only a pointer to the memory region to be freed as an argument.您正确地注意到 C 运行时free function 仅将指向 memory 区域的指针作为参数释放。

However, you don't call this directly.但是,您不直接调用它。 In fact Rust has a layer that abstracts away the actual memory allocator being used: std::alloc::GlobalAlloc .事实上 Rust 有一个层抽象出实际使用的 memory 分配器: std::alloc::GlobalAlloc

The reason for providing such an abstraction is to allow other allocators to be used, and in fact it is quite easy to swap out the default OS provided allocator.提供这样一个抽象的原因是允许使用其他分配器,实际上很容易换掉操作系统提供的默认分配器。

It would be quite limiting to require that any allocator keeps track of the length of blocks to allow them to be freed without supplying the length to the deallocation function, so the general deallocation function requires the length as well.要求任何分配器跟踪块的长度以允许在不向释放 function 提供长度的情况下释放它们是非常有限的,因此一般释放 function 也需要长度。

You might be interested to know that C++ has a similar abstraction .您可能有兴趣知道 C++ 具有类似的抽象 This answer provides some more discussion about why it could be preferable to require the application to keep track of the lengths of allocated memory regions rather than the heap manager.这个答案提供了更多关于为什么要求应用程序跟踪分配的 memory 区域而不是堆管理器的长度的更多讨论。

If we check the type of Box::from_raw , we see that it construct a Box<u8> from a raw *mut u8 .如果我们检查Box::from_raw的类型,我们会看到它从原始*mut u8构造了一个Box<u8> One would need a *mut [u8] (fat pointer to slice) in order to construct a Box<[u8]> (which is what we have in the very beginning).需要一个*mut [u8] (指向切片的胖指针)来构造一个Box<[u8]> (这是我们一开始就有的)。

And drop ping a Box<u8> will (at best) only release one byte of memory (if not causing a runtime error), while drop ping a Box<[u8]> correctly releases all the memory.并且drop ping a Box<u8>将(充其量)仅释放 memory 的一个字节(如果不导致运行时错误),而drop ping Box<[u8]>正确释放所有 memory。

No, what you do is undefined behavior , it's mandatory that the type between into_raw() and from_raw() match.不,您所做的是未定义的行为into_raw()from_raw()之间的类型必须匹配。 Rust alloc API doesn't require the allocator to remember any information, and so the allocation implementation will expect correctness of all information pass to it. Rust alloc API 不需要分配器记住任何信息,因此分配实现将期望传递给它的所有信息的正确性。

In your example, *mut u8 and *mut [u8] are a totally different type and so have different layout.在您的示例中, *mut u8*mut [u8]是完全不同的类型,因此具有不同的布局。

Also, mismatch the type could prevent destructor to run properly.此外,类型不匹配可能会阻止析构函数正常运行。

You can't use from_raw() to destruct any pointer like C free() using void * .您不能使用from_raw()来破坏任何指针,例如 C free()使用void *

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

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