mirror of
https://github.com/neovim/neovim.git
synced 2024-12-23 20:55:18 -07:00
refactor: free more reachable memory with EXITFREE (#26349)
Discovered using __sanitizer_print_memory_profile().
This commit is contained in:
parent
983defd284
commit
f6e5366d00
@ -106,22 +106,37 @@ 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);
|
||||
|
||||
// Destroy `ui`.
|
||||
XFREE_CLEAR(ui->term_name);
|
||||
xfree(ui);
|
||||
remote_ui_destroy(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.
|
||||
void remote_ui_wait_for_attach(bool only_stdio)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -53,13 +53,25 @@ static uint64_t next_chan_id = CHAN_STDERR + 1;
|
||||
/// Teardown the module
|
||||
void channel_teardown(void)
|
||||
{
|
||||
Channel *channel;
|
||||
|
||||
map_foreach_value(&channels, channel, {
|
||||
channel_close(channel->id, kChannelPartAll, NULL);
|
||||
Channel *chan;
|
||||
map_foreach_value(&channels, chan, {
|
||||
channel_close(chan->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
|
||||
///
|
||||
/// @param id The channel id
|
||||
@ -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)) {
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"));
|
||||
|
Loading…
Reference in New Issue
Block a user