Closing libUV Handles Correctly
我试图找出如何解决在Valgrind中运行该程序时遇到的内存泄漏问题。
确定如何正确释放它们。
我尝试在nShell_Connect上释放它们,但是这导致libUV中止该程序。 我尝试在
(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | #include"nPort.h" #include"nShell-main.h" void nShell_Close( uv_handle_t * term_handle ){ } void nShell_Connect(uv_connect_t * term_handle, int status){ uv_close((uv_handle_t *) term_handle, 0); } nError * nShell_client_main(nShell * n_shell, uv_loop_t * n_shell_loop){ int uv_error = 0; nError * n_error = 0; uv_tcp_t * n_shell_socket = 0; uv_connect_t * n_shell_connect = 0; struct sockaddr_in dest_addr; n_shell_socket = malloc(sizeof(uv_tcp_t)); if (!n_shell_socket){ // handle error } uv_error = uv_tcp_init(n_shell_loop, n_shell_socket); if (uv_error){ // handle error } uv_error = uv_ip4_addr("127.0.0.1", NPORT, &dest_addr); if (uv_error){ // handle error } n_shell_connect = malloc(sizeof(uv_connect_t)); if (!n_shell_connect){ // handle error } uv_error = uv_tcp_connect(n_shell_connect, n_shell_socket, (struct sockaddr *) &dest_addr, nShell_Connect); if (uv_error){ // handle error } uv_error = uv_run(n_shell_loop, UV_RUN_DEFAULT); if (uv_error){ // handle error } return 0; } nError * nShell_loop_main(nShell * n_shell){ int uv_error = 0; nError * n_error = 0; uv_loop_t * n_shell_loop = 0; n_shell_loop = malloc(sizeof(uv_loop_t)); if (!n_shell_loop){ // handle error } uv_error = uv_loop_init(n_shell_loop); if (uv_error){ // handle error } n_error = nShell_client_main(n_shell, n_shell_loop); if (n_error){ // handle error } uv_loop_close(n_shell_loop); free(n_shell_loop); return 0; } |
该断言发生在以下代码摘录的switch语句的末尾(摘自Github上Joyent的libUV页面):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); handle->flags |= UV_CLOSING; handle->close_cb = close_cb; switch (handle->type) { case UV_NAMED_PIPE: uv__pipe_close((uv_pipe_t*)handle); break; case UV_TTY: uv__stream_close((uv_stream_t*)handle); break; case UV_TCP: uv__tcp_close((uv_tcp_t*)handle); break; case UV_UDP: uv__udp_close((uv_udp_t*)handle); break; case UV_PREPARE: uv__prepare_close((uv_prepare_t*)handle); break; case UV_CHECK: uv__check_close((uv_check_t*)handle); break; case UV_IDLE: uv__idle_close((uv_idle_t*)handle); break; case UV_ASYNC: uv__async_close((uv_async_t*)handle); break; case UV_TIMER: uv__timer_close((uv_timer_t*)handle); break; case UV_PROCESS: uv__process_close((uv_process_t*)handle); break; case UV_FS_EVENT: uv__fs_event_close((uv_fs_event_t*)handle); break; case UV_POLL: uv__poll_close((uv_poll_t*)handle); break; case UV_FS_POLL: uv__fs_poll_close((uv_fs_poll_t*)handle); break; case UV_SIGNAL: uv__signal_close((uv_signal_t*) handle); /* Signal handles may not be closed immediately. The signal code will */ /* itself close uv__make_close_pending whenever appropriate. */ return; default: assert(0); // assertion is happening here } uv__make_close_pending(handle); } |
我可以手动调用
直到它的关闭回调被调用时,libuv才使用句柄完成。那是释放手柄的确切时间。
我看到您呼叫
如果要关闭循环并关闭所有句柄,则需要执行以下操作:
-
使用
uv_stop 停止循环 -
在所有未关闭的句柄上使用
uv_walk 并调用uv_close -
使用
uv_run 再次运行循环,以便调用所有关闭的回调,然后可以释放这些回调中的内存 -
调用
uv_loop_close ,现在应该返回0
我终于想出了如何停止循环并清理所有句柄的方法。
我创建了一堆句柄和SIGINT信号句柄:
1 2 3 | uv_signal_t *sigint = new uv_signal_t; uv_signal_init(uv_default_loop(), sigint); uv_signal_start(sigint, on_sigint_received, SIGINT); |
收到SIGINT(按下控制台中的Ctrl + C)时,将调用
1 2 3 4 5 6 7 8 | void on_sigint_received(uv_signal_t *handle, int signum) { int result = uv_loop_close(handle->loop); if (result == UV_EBUSY) { uv_walk(handle->loop, on_uv_walk, NULL); } } |
它触发一个回调函数
1 2 3 4 | void on_uv_walk(uv_handle_t* handle, void* arg) { uv_close(handle, on_uv_close); } |
它尝试关闭每个打开的libuv句柄。
注意:正如saghul所述,我不会在
在
1 2 3 4 5 6 7 | void on_uv_close(uv_handle_t* handle) { if (handle != NULL) { delete handle; } } |
之后,libuv没有打开句柄并完成循环(从
1 2 3 4 5 6 7 8 9 10 11 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); int result = uv_loop_close(uv_default_loop()); if (result) { cerr <<"failed to close libuv loop:" << uv_err_name(result) << endl; } else { cout <<"libuv loop is closed successfully! "; } |