aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-12-02 07:55:44 +0800
committerGitHub <noreply@github.com>2023-12-02 07:55:44 +0800
commitf6e5366d0077e9f171651f37282cb5c47629d1b6 (patch)
treefb7f29ea11c7c122f3e4404c9473b8fff1dc5eaf
parent983defd284f5941c870d7868cdb60587a98ab348 (diff)
downloadrneovim-f6e5366d0077e9f171651f37282cb5c47629d1b6.tar.gz
rneovim-f6e5366d0077e9f171651f37282cb5c47629d1b6.tar.bz2
rneovim-f6e5366d0077e9f171651f37282cb5c47629d1b6.zip
refactor: free more reachable memory with EXITFREE (#26349)
Discovered using __sanitizer_print_memory_profile().
-rw-r--r--src/nvim/api/ui.c25
-rw-r--r--src/nvim/autocmd.c5
-rw-r--r--src/nvim/channel.c29
-rw-r--r--src/nvim/eval.c4
-rw-r--r--src/nvim/grid.c5
-rw-r--r--src/nvim/map_defs.h17
-rw-r--r--src/nvim/marktree.c1
-rw-r--r--src/nvim/memory.c25
-rw-r--r--src/nvim/msgpack_rpc/channel.c5
-rw-r--r--src/nvim/msgpack_rpc/helpers.c8
-rw-r--r--src/nvim/option.c3
-rw-r--r--src/nvim/os/env.c11
-rw-r--r--src/nvim/os/input.c7
-rw-r--r--src/nvim/ui.c2
-rw-r--r--src/nvim/ui_client.c9
-rw-r--r--src/nvim/ui_compositor.c9
16 files changed, 149 insertions, 16 deletions
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 7e64ce9cd1..b73c026d57 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -106,21 +106,36 @@ static void mpack_str(char **buf, const char *str)
*buf += len;
}
+static void remote_ui_destroy(UI *ui)
+ FUNC_ATTR_NONNULL_ALL
+{
+ UIData *data = ui->data;
+ kv_destroy(data->call_buf);
+ XFREE_CLEAR(ui->term_name);
+ xfree(ui);
+}
+
void remote_ui_disconnect(uint64_t channel_id)
{
UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
if (!ui) {
return;
}
- UIData *data = ui->data;
- kv_destroy(data->call_buf);
pmap_del(uint64_t)(&connected_uis, channel_id, NULL);
ui_detach_impl(ui, channel_id);
+ remote_ui_destroy(ui);
+}
- // Destroy `ui`.
- XFREE_CLEAR(ui->term_name);
- xfree(ui);
+#ifdef EXITFREE
+void remote_ui_free_all_mem(void)
+{
+ UI *ui;
+ map_foreach_value(&connected_uis, ui, {
+ remote_ui_destroy(ui);
+ });
+ map_destroy(uint64_t, &connected_uis);
}
+#endif
/// Wait until ui has connected on stdio channel if only_stdio
/// is true, otherwise any channel.
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 7d635984b8..46a08c5706 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -2573,6 +2573,11 @@ void do_autocmd_uienter(uint64_t chanid, bool attached)
{
static bool recursive = false;
+#ifdef EXITFREE
+ if (entered_free_all_mem) {
+ return;
+ }
+#endif
if (starting == NO_SCREEN) {
return; // user config hasn't been sourced yet
}
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 849b63ae31..24793bcb2a 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -53,12 +53,24 @@ static uint64_t next_chan_id = CHAN_STDERR + 1;
/// Teardown the module
void channel_teardown(void)
{
- Channel *channel;
+ Channel *chan;
+ map_foreach_value(&channels, chan, {
+ channel_close(chan->id, kChannelPartAll, NULL);
+ });
+}
- map_foreach_value(&channels, channel, {
- channel_close(channel->id, kChannelPartAll, NULL);
+#ifdef EXITFREE
+void channel_free_all_mem(void)
+{
+ Channel *chan;
+ map_foreach_value(&channels, chan, {
+ channel_destroy(chan);
});
+ map_destroy(uint64_t, &channels);
+
+ callback_free(&on_print);
}
+#endif
/// Closes a channel
///
@@ -260,9 +272,8 @@ void callback_reader_start(CallbackReader *reader, const char *type)
reader->type = type;
}
-static void free_channel_event(void **argv)
+static void channel_destroy(Channel *chan)
{
- Channel *chan = argv[0];
if (chan->is_rpc) {
rpc_free(chan);
}
@@ -275,11 +286,17 @@ static void free_channel_event(void **argv)
callback_reader_free(&chan->on_stderr);
callback_free(&chan->on_exit);
- pmap_del(uint64_t)(&channels, chan->id, NULL);
multiqueue_free(chan->events);
xfree(chan);
}
+static void free_channel_event(void **argv)
+{
+ Channel *chan = argv[0];
+ pmap_del(uint64_t)(&channels, chan->id, NULL);
+ channel_destroy(chan);
+}
+
static void channel_destroy_early(Channel *chan)
{
if ((chan->id != --next_chan_id)) {
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 6786316b8e..ae34f5715f 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -500,6 +500,10 @@ static void evalvars_clear(void)
p->vv_list = NULL;
}
}
+
+ partial_unref(vvlua_partial);
+ vimvars[VV_LUA].vv_partial = vvlua_partial = NULL;
+
hash_clear(&vimvarht);
hash_init(&vimvarht); // garbage_collect() will access it
hash_clear(&compat_hashtab);
diff --git a/src/nvim/grid.c b/src/nvim/grid.c
index 2ef89b778e..58884e7f72 100644
--- a/src/nvim/grid.c
+++ b/src/nvim/grid.c
@@ -879,15 +879,20 @@ void grid_free(ScreenGrid *grid)
grid->line_offset = NULL;
}
+#ifdef EXITFREE
/// Doesn't allow reinit, so must only be called by free_all_mem!
void grid_free_all_mem(void)
{
grid_free(&default_grid);
+ grid_free(&msg_grid);
+ XFREE_CLEAR(msg_grid.dirty_col);
xfree(linebuf_char);
xfree(linebuf_attr);
xfree(linebuf_vcol);
xfree(linebuf_scratch);
+ set_destroy(glyph, &glyph_cache);
}
+#endif
/// (Re)allocates a window grid if size changed while in ext_multigrid mode.
/// Updates size, offsets and handle for the grid regardless.
diff --git a/src/nvim/map_defs.h b/src/nvim/map_defs.h
index 147c03327a..f3c4e4ea95 100644
--- a/src/nvim/map_defs.h
+++ b/src/nvim/map_defs.h
@@ -172,9 +172,14 @@ MAP_DECLS(ColorKey, ColorItem)
#define set_put_ref(T, set, key, key_alloc) set_put_##T(set, key, key_alloc)
#define set_put_idx(T, set, key, status) mh_put_##T(set, key, status)
#define set_del(T, set, key) set_del_##T(set, key)
-#define set_destroy(T, set) (xfree((set)->keys), xfree((set)->h.hash))
-#define set_clear(T, set) mh_clear(&(set)->h)
#define set_size(set) ((set)->h.size)
+#define set_clear(T, set) mh_clear(&(set)->h)
+#define set_destroy(T, set) \
+ do { \
+ xfree((set)->keys); \
+ xfree((set)->h.hash); \
+ *(set) = (Set(T)) SET_INIT; \
+ } while (0)
#define map_get(T, U) map_get_##T##U
#define map_has(T, map, key) set_has(T, &(map)->set, key)
@@ -182,9 +187,13 @@ MAP_DECLS(ColorKey, ColorItem)
#define map_ref(T, U) map_ref_##T##U
#define map_put_ref(T, U) map_put_ref_##T##U
#define map_del(T, U) map_del_##T##U
-#define map_destroy(T, map) (set_destroy(T, &(map)->set), xfree((map)->values))
-#define map_clear(T, map) set_clear(T, &(map)->set)
#define map_size(map) set_size(&(map)->set)
+#define map_clear(T, map) set_clear(T, &(map)->set)
+#define map_destroy(T, map) \
+ do { \
+ set_destroy(T, &(map)->set); \
+ XFREE_CLEAR((map)->values); \
+ } while (0)
#define pmap_get(T) map_get(T, ptr_t)
#define pmap_put(T) map_put(T, ptr_t)
diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c
index b555b3b4ae..f14da1b605 100644
--- a/src/nvim/marktree.c
+++ b/src/nvim/marktree.c
@@ -1117,7 +1117,6 @@ void marktree_clear(MarkTree *b)
b->root = NULL;
}
map_destroy(uint64_t, b->id2node);
- *b->id2node = (PMap(uint64_t)) MAP_INIT;
b->n_keys = 0;
assert(b->n_nodes == 0);
}
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 35ae6afde7..52fdf9f923 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -9,9 +9,12 @@
#include <time.h>
#include "nvim/api/extmark.h"
+#include "nvim/api/private/helpers.h"
+#include "nvim/api/ui.h"
#include "nvim/arglist.h"
#include "nvim/ascii_defs.h"
#include "nvim/buffer_updates.h"
+#include "nvim/channel.h"
#include "nvim/context.h"
#include "nvim/decoration_provider.h"
#include "nvim/drawline.h"
@@ -23,14 +26,19 @@
#include "nvim/insexpand.h"
#include "nvim/lua/executor.h"
#include "nvim/main.h"
+#include "nvim/map_defs.h"
#include "nvim/mapping.h"
#include "nvim/memfile.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/option_vars.h"
+#include "nvim/os/input.h"
#include "nvim/sign.h"
#include "nvim/state_defs.h"
+#include "nvim/statusline.h"
#include "nvim/ui.h"
+#include "nvim/ui_client.h"
+#include "nvim/ui_compositor.h"
#include "nvim/usercmd.h"
#include "nvim/vim_defs.h"
@@ -670,6 +678,7 @@ char *arena_memdupz(Arena *arena, const char *buf, size_t size)
# include "nvim/grid.h"
# include "nvim/mark.h"
# include "nvim/msgpack_rpc/channel.h"
+# include "nvim/msgpack_rpc/helpers.h"
# include "nvim/ops.h"
# include "nvim/option.h"
# include "nvim/os/os.h"
@@ -738,6 +747,7 @@ void free_all_mem(void)
free_all_marks();
alist_clear(&global_alist);
free_homedir();
+ free_envmap();
free_users();
free_search_patterns();
free_old_sub();
@@ -792,6 +802,7 @@ void free_all_mem(void)
}
}
+ channel_free_all_mem();
eval_clear();
api_extmark_free_all_mem();
ctx_free_all();
@@ -815,8 +826,14 @@ void free_all_mem(void)
buf = bufref_valid(&bufref) ? nextbuf : firstbuf;
}
+ map_destroy(int, &buffer_handles);
+ map_destroy(int, &window_handles);
+ map_destroy(int, &tabpage_handles);
+
// free screenlines (can't display anything now!)
grid_free_all_mem();
+ stl_clear_click_defs(tab_page_click_defs, tab_page_click_defs_size);
+ xfree(tab_page_click_defs);
clear_hl_tables(false);
@@ -824,10 +841,18 @@ void free_all_mem(void)
decor_free_all_mem();
drawline_free_all_mem();
+ input_free_all_mem();
+
+ if (ui_client_channel_id) {
+ ui_client_free_all_mem();
+ }
+ remote_ui_free_all_mem();
ui_free_all_mem();
+ ui_comp_free_all_mem();
nlua_free_all_mem();
rpc_free_all_mem();
+ msgpack_rpc_helpers_free_all_mem();
// should be last, in case earlier free functions deallocates arenas
arena_free_reuse_blks();
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index acc21bbf7e..2336853609 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -751,6 +751,7 @@ const char *get_client_info(Channel *chan, const char *key)
return NULL;
}
+#ifdef EXITFREE
void rpc_free_all_mem(void)
{
cstr_t key;
@@ -758,4 +759,8 @@ void rpc_free_all_mem(void)
xfree((void *)key);
});
set_destroy(cstr_t, &event_strings);
+
+ msgpack_sbuffer_destroy(&out_buffer);
+ multiqueue_free(ch_before_blocking_events);
}
+#endif
diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c
index d2be321e7a..3162269df6 100644
--- a/src/nvim/msgpack_rpc/helpers.c
+++ b/src/nvim/msgpack_rpc/helpers.c
@@ -27,6 +27,14 @@ void msgpack_rpc_helpers_init(void)
msgpack_sbuffer_init(&sbuffer);
}
+#ifdef EXITFREE
+void msgpack_rpc_helpers_free_all_mem(void)
+{
+ msgpack_zone_destroy(&zone);
+ msgpack_sbuffer_destroy(&sbuffer);
+}
+#endif
+
typedef struct {
const msgpack_object *mobj;
Object *aobj;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 882722a575..7a7cda2fa0 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -583,6 +583,9 @@ void free_all_options(void)
}
free_operatorfunc_option();
free_tagfunc_option();
+ XFREE_CLEAR(fenc_default);
+ XFREE_CLEAR(p_term);
+ XFREE_CLEAR(p_ttytype);
}
#endif
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index b1e680e469..6c14f3d593 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -510,6 +510,17 @@ void free_homedir(void)
xfree(homedir);
}
+void free_envmap(void)
+{
+ cstr_t name;
+ ptr_t e;
+ map_foreach(&envmap, name, e, {
+ xfree((char *)name);
+ xfree(e);
+ });
+ map_destroy(cstr_t, &envmap);
+}
+
#endif
/// Call expand_env() and store the result in an allocated string.
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 7c404aa736..69d328754b 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -74,6 +74,13 @@ void input_stop(void)
stream_close(&read_stream, NULL, NULL);
}
+#ifdef EXITFREE
+void input_free_all_mem(void)
+{
+ rbuffer_free(input_buffer);
+}
+#endif
+
static void cursorhold_event(void **argv)
{
event_T event = State & MODE_INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD;
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index b068847e85..cb4ebb5c3b 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -134,6 +134,8 @@ void ui_free_all_mem(void)
free_ui_event_callback(event_cb);
})
map_destroy(uint32_t, &ui_event_cbs);
+
+ multiqueue_free(resize_events);
}
#endif
diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c
index a7a1c5912a..eb32c16881 100644
--- a/src/nvim/ui_client.c
+++ b/src/nvim/ui_client.c
@@ -210,3 +210,12 @@ void ui_client_event_raw_line(GridLineEvent *g)
tui_raw_line(tui, grid, row, startcol, endcol, clearcol, g->cur_attr, lineflags,
(const schar_T *)grid_line_buf_char, grid_line_buf_attr);
}
+
+#ifdef EXITFREE
+void ui_client_free_all_mem(void)
+{
+ tui_free_all_mem(tui);
+ xfree(grid_line_buf_char);
+ xfree(grid_line_buf_attr);
+}
+#endif
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index b698e017dc..c4078d6f63 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -60,6 +60,15 @@ void ui_comp_init(void)
curgrid = &default_grid;
}
+#ifdef EXITFREE
+void ui_comp_free_all_mem(void)
+{
+ kv_destroy(layers);
+ xfree(linebuf);
+ xfree(attrbuf);
+}
+#endif
+
void ui_comp_syn_init(void)
{
dbghl_normal = syn_check_group(S_LEN("RedrawDebugNormal"));