You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

libuv中uv_write动态分配缓冲区的内存释放方法问询

如何在libuv的uv_write回调中释放缓冲区内存?

我在使用libuv的uv_write时遇到了内存管理的问题:根据文档说明,uv_write(包括uv_write2)用到的缓冲区内存必须在回调触发前保持有效。我现在的代码是这样分配缓冲区的:

void write_to_stream(uv_stream_t* stream) {
  uv_write_t* write_req = new uv_write_t;
  uv_buf_t buf{};
  buf.base = new char[1024];
  buf.len = 1024;
  // fill the buffer
  uv_write(write_req, stream, &buf, 1, on_write);
}

但回调函数on_write的签名是void on_write(uv_write_t* req, int status),没办法直接拿到缓冲区的指针,不知道该怎么释放new char[1024]分配的内存:

void on_write(uv_write_t* req, int status) {
  // how to find the memory allocated for req's buffer?
  delete[] ???;
}

请问这种情况下,正确的内存释放方式是什么?


这是libuv开发里很常见的内存管理痛点,核心思路就是把缓冲区和请求对象绑定在一起,让回调能通过请求对象找到要释放的内存。这里有两种实用的方案,你可以根据场景选:

方案1:用uv_write_t自带的data字段存缓冲区指针

libuv的所有请求结构体(包括uv_write_t)都有一个void* data成员,专门用来存用户自定义数据。我们可以直接把缓冲区的指针存在这里,回调时再取出来:

修改后的写入函数:

void write_to_stream(uv_stream_t* stream) {
  uv_write_t* write_req = new uv_write_t;
  uv_buf_t buf{};
  buf.base = new char[1024];
  buf.len = 1024;
  
  // 把缓冲区指针绑定到请求的data字段
  write_req->data = buf.base;
  
  // fill the buffer
  uv_write(write_req, stream, &buf, 1, on_write);
}

回调函数中释放内存:

void on_write(uv_write_t* req, int status) {
  // 从data字段取出缓冲区指针并强制类型转换
  char* buf_base = static_cast<char*>(req->data);
  // 先释放缓冲区内存
  delete[] buf_base;
  // 再释放请求对象本身
  delete req;
}

这种方法简单直接,不需要额外定义结构体,适合只需要传递缓冲区指针的简单场景。

方案2:自定义结构体继承uv_write_t(扩展性更强)

如果你的写入操作需要携带更多上下文信息(比如多个缓冲区、业务ID、关联的流指针等),更优雅的方式是定义一个自己的结构体,继承uv_write_t,把所有需要的信息都装进去:

自定义请求结构体:

struct MyWriteReq : public uv_write_t {
  uv_buf_t buf; // 直接存储缓冲区结构体
  // 还可以添加其他你需要的字段,比如:
  // int business_id;
  // uv_stream_t* target_stream;
};

修改后的写入函数:

void write_to_stream(uv_stream_t* stream) {
  MyWriteReq* write_req = new MyWriteReq;
  write_req->buf.base = new char[1024];
  write_req->buf.len = 1024;
  
  // fill the buffer
  uv_write(write_req, stream, &write_req->buf, 1, on_write);
}

回调函数中释放内存:

void on_write(uv_write_t* req, int status) {
  // 将uv_write_t指针转换为自定义的请求结构体指针
  MyWriteReq* my_req = static_cast<MyWriteReq*>(req);
  // 释放缓冲区
  delete[] my_req->buf.base;
  // 释放自定义请求对象
  delete my_req;
}

这种方式扩展性拉满,后续如果要加更多上下文,直接在结构体里加字段就行,不用改太多逻辑。

额外注意:

  • 释放顺序别搞反:先释放缓冲区内存,再释放请求对象,避免出现野指针。
  • 如果是用C语言开发(不是C++),可以用结构体嵌套的方式(把uv_write_t作为自定义结构体的第一个成员),同样能安全地做类型转换,思路和上面一致。

内容的提问来源于stack exchange,提问作者surrz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:19:10