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
相关产品推荐
相关产品推荐

