“String”总是分配在堆上吗?

Den*_*ive 4 string heap-memory stack-memory rust

在这个Rust 文档中,写道:

字符串是在堆上分配的。

但是,当我查看内存映射时,我发现它是在堆栈中分配的......

让我们考虑下面的基本 Rust 源文件:

// rustc -o string_vs_str -C opt-level=0 -C debuginfo=2 main.rs

fn main() {
    let my_string: String = String::from("abc");
    let my_str: &str = "def";
    println!("{}{}", my_string, my_str);
    let my_string_str: &str = my_string.as_str();
    println!("my_string_str: {}", my_string_str);
}
Run Code Online (Sandbox Code Playgroud)

让我们根据以下命令在可执行文件上执行 RUST-GDB:

# rust-gdb --batch --command=test.gdb --args ./string_vs_str

set width 0
set height 0
set verbose off

### Set 2 breakpoints
b main.rs:6
b main.rs:8

### Start the process
r

### Display the memory mapping into the file "map.txt"
set logging redirect on
set logging file map.txt
set logging overwrite on
set logging enabled on
info proc map
set logging enabled off

### Get information about "my_string"
echo == my_string ==\n
print my_string
ptype my_string
print &my_string
print my_string.vec
c

### Get information about "my_str"
echo == my_str ==\n
print my_str
ptype my_str
print &my_str
print my_str.length
print my_str.data_ptr
Run Code Online (Sandbox Code Playgroud)

结果如下:

# rust-gdb --batch --command=test.gdb --args ./string_vs_str

set width 0
set height 0
set verbose off

### Set 2 breakpoints
b main.rs:6
b main.rs:8

### Start the process
r

### Display the memory mapping into the file "map.txt"
set logging redirect on
set logging file map.txt
set logging overwrite on
set logging enabled on
info proc map
set logging enabled off

### Get information about "my_string"
echo == my_string ==\n
print my_string
ptype my_string
print &my_string
print my_string.vec
c

### Get information about "my_str"
echo == my_str ==\n
print my_str
ptype my_str
print &my_str
print my_str.length
print my_str.data_ptr
Run Code Online (Sandbox Code Playgroud)

(记录的)文件“ ”的内容map.txt是:

Breakpoint 1, main::main () at main.rs:6
6       println!("{}{}", my_string, my_str);
== my_string ==
$1 = "abc"
type = struct alloc::string::String {
  vec: alloc::vec::Vec<u8, alloc::alloc::Global>,
}
$2 = (*mut alloc::string::String) 0x7fffffffd960
$3 = Vec(size=3) = {97, 98, 99}
abcdef

Breakpoint 2, main::main () at main.rs:8
8       println!("my_string_str: {}", my_string_str);
== my_str ==
$4 = "def"
type = struct &str {
  data_ptr: *mut u8,
  length: usize,
}
$5 = (*mut &str) 0x7fffffffd978
$6 = 3
$7 = (*mut u8) 0x55555559304f
Run Code Online (Sandbox Code Playgroud)

请注意:我删除了一些我认为不重要的行。

除非我记错了:

  • 头部开始于0x5555555a5000并结束于0x5555555c6000
  • 堆栈开始于0x7ffffffde000并结束于0x7ffffffff000
  • 该变量my_string分配在0x7fffffffd960
  • 该变量my_str分配在0x7fffffffd978

好的。因此,除非我弄错了,否则my_string和 都my_str在堆栈中分配:

VAR my_string

my_string0x7fffffffd960

process 11932
Mapped address spaces:

          Start Addr           End Addr       Size     Offset  Perms  objfile
      ...
      0x5555555a5000     0x5555555c6000    0x21000        0x0  rw-p   [heap]
      0x7ffff7d5c000     0x7ffff7d5f000     0x3000        0x0  rw-p   
      ...
      0x7ffffffde000     0x7ffffffff000    0x21000        0x0  rw-p   [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0  --xp   [vsyscall]
Run Code Online (Sandbox Code Playgroud)

因此:0x7ffffffde000 < &my_string < 0x7ffffffff000=>my_string在堆栈中分配。

VAR my_str

my_str.data_ptr0x7fffffffd978

$ value="7fffffffd960"  # address of my_string
$ start="7ffffffde000"  # start of the stack
$ stop="7ffffffff000"   # end of the stack
$ echo "obase=16;ibase=16;${value^^} > ${start^^}" | bc
1
$ echo "obase=16;ibase=16;${value^^} < ${stop^^}" | bc
1
Run Code Online (Sandbox Code Playgroud)

因此:0x7ffffffde000 < &my_str.data_ptr < 0x7ffffffff000=>my_str.data_ptr在堆栈中分配。

my_str.length0x55555559304f

$ value="7fffffffd978"  # address of my_str.data_ptr
$ start="7ffffffde000"  # start of the stack
$ stop="7ffffffff000"   # end of the stack
$ echo "obase=16;ibase=16;${value^^} > ${start^^}" | bc
1
$ echo "obase=16;ibase=16;${value^^} < ${stop^^}" | bc
1
Run Code Online (Sandbox Code Playgroud)

因此:&my_str.length不在堆栈中分配,也不在堆中分配。

结论:

定义“ ”的结构体str在栈中分配。

定义“字符串”内容的向量也在堆栈中分配。

这个实验有什么问题吗?

Cha*_*man 7

和变量本身在堆栈上分配(长度String&str数据指针和容量String)。但它们指向的数据分配在 的堆上String,并分配.rodata给您的&str

要查看这一点,请打印my_string.vec.buf.ptr.pointer.pointer(是的,很长)和my_str.data_ptr. 您将看到第一个指向堆,第二个指向可执行文件。这些是数据指针。