簡體   English   中英

在沒有重新分配的情況下將Vec轉換為FFI的正確方法是什么?

[英]What is the correct way to convert a Vec for FFI without reallocation?

我需要在FFI中傳遞一個元素的Vec 通過實驗,我發現了一些有趣的觀點。 我開始給FFI全部3: ptrlencapacity以便我可以重建Vec以便以后銷毀它:

let ptr = vec.as_mut_ptr();
let len = vec.len();
let cap = vec.capacity();
mem::forget(vec);
extern_fn(ptr, len, cap);

// ...

pub unsafe extern "C" fn free(ptr: *mut u8, len: usize, cap: usize) {
    let _ = Vec::from_raw_parts(ptr, len, cap);
}

我想擺脫capacity因為它對我的前端沒用; 它只是為了讓我可以重建我的矢量以釋放記憶。

Vec::shrink_to_fit()很有吸引力,因為它似乎消除了處理容量的需要。 不幸的是,它上面的文檔並不保證它會使len == capacity ,因此我假設在from_raw_parts()期間可能會觸發Undefined Behavior。

into_boxed_slice()似乎保證它將從文檔中獲得len == capacity ,所以我接下來使用它。 如果我錯了,請糾正我 問題是它似乎不能保證不重新分配。 這是一個簡單的程序:

fn main() {
    let mut v = Vec::with_capacity(1000);
    v.push(100u8);
    v.push(110);
    let ptr_1 = v.as_mut_ptr();
    let mut boxed_slice = v.into_boxed_slice();
    let ptr_2 = boxed_slice.as_mut_ptr();
    let ptr_3 = Box::into_raw(boxed_slice);
    println!("{:?}. {:?}. {:?}", ptr_1, ptr_2, ptr_3);
}

在操場上 ,它打印:

rustc 1.14.0 (e8a012324 2016-12-16)
0x7fdc9841b000. 0x7fdc98414018. 0x7fdc98414018

如果必須找到新的內存而不是在不造成副本的情況下脫掉額外的容量,這就不好了。

有沒有其他方法可以將我的矢量傳遞到FFI(到C)而不傳遞容量? 似乎into_boxed_slice()是我需要的,但為什么它涉及重新分配和復制數據?

原因相對簡單。

現代內存分配器將在“大小”平板中分離分配,其中每個平板負責處理給定范圍的大小。 例如:

  • 8字節slab:1到8個字節的任何內容
  • 16字節slab:從9到16字節的任何內容
  • 24字節slab:從17到24字節的任何內容
  • ...

當你分配內存時,你要求一個給定的大小,分配器找到正確的slab,從中獲取一個塊,然后返回你的指針。

當你釋放內存時...你怎么期望分配器找到合適的平板? 有兩種解決方案:

  • 分配器有辦法搜索包含你的內存范圍的slab,不知何故,它涉及通過slab的線性搜索或某種全局查找表或...
  • 告訴分配器什么是分配塊的大小

這里顯而易見的是,C接口( freerealloc )相當低於標准,因此Rust希望使用更有效的接口,即onus在調用者上的接口。


所以,你有兩個選擇:

  1. 通過容量
  2. 確保長度和容量相等

如您所知,(2)可能需要新的分配,這是非常不受歡迎的。 (1)可以通過全程傳遞容量來實現,也可以在某個時候存儲容量,然后在需要時檢索它。

而已。 你必須評估你的權衡。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM