裸指针的分类

  1. *mut T 可变裸指针
  2. *const T 不可变裸指针

如何获取裸指针?

1. 从引用获取

  1. struct A;
  2. let a = &A;
  3. let o: *const A = a as *const A;

2. 堆上分配

  1. struct A;
  2. let a = A;
  3. let a: *const A = Box::into_raw(Box::new(a));

3. 内存分配器

  1. GlobalAlloc::alloc

裸指针的一些特性

1. 不释放所指向的对象

  1. struct A;
  2. impl Drop for A {
  3. fn drop(&mut self) {
  4. println!("drop A...");
  5. }
  6. }
  7. fn main() {
  8. let a = A;
  9. let b = Box::into_raw(Box::new(a));
  10. }

执行这段代码并不会打印drop A。换句话说,释放裸指针并不会释放它所指向的对象。裸指针b的释放不会同时释放其指向的内存结构。

补充:令Rust内存泄漏的几种方法:

  1. Box::leak(Box::new(a))
  2. mem::forget(a)
  3. ManuallyDrop::new(a)

这几个底层都是ManuallyDrop,任何被这个struct封装的结构都不会被释放。

2. 解引用裸指针是不安全的

  1. fn main() {
  2. let mut a: i32 = 99;
  3. add_one(&mut a as *mut i32);
  4. println!("{}",a);
  5. }
  6. fn add_one(pointer: *mut i32) {
  7. unsafe { *pointer += 1 };
  8. }
  9. // 100

3. 解引用不能move出指针

  1. struct A;
  2. fn main() {
  3. let a = A;
  4. let x = &a as *const A;
  5. // 这里报错
  6. let mm :A = unsafe { *x };
  7. }

read可以吗:

  1. struct A;
  2. fn main() {
  3. let a = A;
  4. let x = &a as *const A;
  5. // let mm:A = unsafe { *x };
  6. let mm:A = unsafe { x.read() };
  7. }

看起来没报错。我们看read这个函数的注释:

/// Reads the value from src without moving it. This leaves the

/// memory in src unchanged.

实际上 read 也不会move原数据。

4. ZST

Box上的ZST的裸指针,打印出来地址是0x1,跟注释里描述的一样,Box::new对于 ZST 实际上是没有发生内存申请的。

裸指针该如何释放呢?

指向栈的裸指针

裸指针指向栈的:指针,内存也会随着栈帧一起释放。

指向堆上的裸指针

Box::into_raw 将返回堆上的裸指针,对于此类指针,内部是 ManuallyDrop ,会阻止堆上内存的释放。我们拿着这样的裸指针,咋释放呢?

1. 从裸指针还原回box
  1. fn main() {
  2. let b = Box::into_raw(Box::new(A));
  3. let o = unsafe { Box::from_raw(b) };
  4. }
  5. struct A;
  6. impl Drop for A {
  7. fn drop(&mut self) {
  8. println!("drop A");
  9. }
  10. }

如此还原Box后,Box释放,内存即释放。

2. 直接释放裸指针

先执行下struct的Drop,就是调用drop_in_place,然后调用dealloc释放内存。

  1. use std::{
  2. alloc::{dealloc, Layout},
  3. ptr::drop_in_place,
  4. };
  5. struct A;
  6. impl Drop for A {
  7. fn drop(&mut self) {
  8. println!("drop AA")
  9. }
  10. }
  11. fn main() {
  12. let a = Box::into_raw(Box::new(A));
  13. unsafe { drop_in_place(a) };
  14. unsafe { dealloc(a as *mut u8, Layout::new::<A>()) };
  15. }