mirror of
https://github.com/neovim/neovim.git
synced 2024-12-24 13:15:09 -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;
|
*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)
|
void remote_ui_disconnect(uint64_t channel_id)
|
||||||
{
|
{
|
||||||
UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
|
UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
|
||||||
if (!ui) {
|
if (!ui) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UIData *data = ui->data;
|
|
||||||
kv_destroy(data->call_buf);
|
|
||||||
pmap_del(uint64_t)(&connected_uis, channel_id, NULL);
|
pmap_del(uint64_t)(&connected_uis, channel_id, NULL);
|
||||||
ui_detach_impl(ui, channel_id);
|
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
|
/// Wait until ui has connected on stdio channel if only_stdio
|
||||||
/// is true, otherwise any channel.
|
/// is true, otherwise any channel.
|
||||||
void remote_ui_wait_for_attach(bool only_stdio)
|
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;
|
static bool recursive = false;
|
||||||
|
|
||||||
|
#ifdef EXITFREE
|
||||||
|
if (entered_free_all_mem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (starting == NO_SCREEN) {
|
if (starting == NO_SCREEN) {
|
||||||
return; // user config hasn't been sourced yet
|
return; // user config hasn't been sourced yet
|
||||||
}
|
}
|
||||||
|
@ -53,13 +53,25 @@ static uint64_t next_chan_id = CHAN_STDERR + 1;
|
|||||||
/// Teardown the module
|
/// Teardown the module
|
||||||
void channel_teardown(void)
|
void channel_teardown(void)
|
||||||
{
|
{
|
||||||
Channel *channel;
|
Channel *chan;
|
||||||
|
map_foreach_value(&channels, chan, {
|
||||||
map_foreach_value(&channels, channel, {
|
channel_close(chan->id, kChannelPartAll, NULL);
|
||||||
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
|
/// Closes a channel
|
||||||
///
|
///
|
||||||
/// @param id The channel id
|
/// @param id The channel id
|
||||||
@ -260,9 +272,8 @@ void callback_reader_start(CallbackReader *reader, const char *type)
|
|||||||
reader->type = 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) {
|
if (chan->is_rpc) {
|
||||||
rpc_free(chan);
|
rpc_free(chan);
|
||||||
}
|
}
|
||||||
@ -275,11 +286,17 @@ static void free_channel_event(void **argv)
|
|||||||
callback_reader_free(&chan->on_stderr);
|
callback_reader_free(&chan->on_stderr);
|
||||||
callback_free(&chan->on_exit);
|
callback_free(&chan->on_exit);
|
||||||
|
|
||||||
pmap_del(uint64_t)(&channels, chan->id, NULL);
|
|
||||||
multiqueue_free(chan->events);
|
multiqueue_free(chan->events);
|
||||||
xfree(chan);
|
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)
|
static void channel_destroy_early(Channel *chan)
|
||||||
{
|
{
|
||||||
if ((chan->id != --next_chan_id)) {
|
if ((chan->id != --next_chan_id)) {
|
||||||
|
@ -500,6 +500,10 @@ static void evalvars_clear(void)
|
|||||||
p->vv_list = NULL;
|
p->vv_list = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial_unref(vvlua_partial);
|
||||||
|
vimvars[VV_LUA].vv_partial = vvlua_partial = NULL;
|
||||||
|
|
||||||
hash_clear(&vimvarht);
|
hash_clear(&vimvarht);
|
||||||
hash_init(&vimvarht); // garbage_collect() will access it
|
hash_init(&vimvarht); // garbage_collect() will access it
|
||||||
hash_clear(&compat_hashtab);
|
hash_clear(&compat_hashtab);
|
||||||
|
@ -879,15 +879,20 @@ void grid_free(ScreenGrid *grid)
|
|||||||
grid->line_offset = NULL;
|
grid->line_offset = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EXITFREE
|
||||||
/// Doesn't allow reinit, so must only be called by free_all_mem!
|
/// Doesn't allow reinit, so must only be called by free_all_mem!
|
||||||
void grid_free_all_mem(void)
|
void grid_free_all_mem(void)
|
||||||
{
|
{
|
||||||
grid_free(&default_grid);
|
grid_free(&default_grid);
|
||||||
|
grid_free(&msg_grid);
|
||||||
|
XFREE_CLEAR(msg_grid.dirty_col);
|
||||||
xfree(linebuf_char);
|
xfree(linebuf_char);
|
||||||
xfree(linebuf_attr);
|
xfree(linebuf_attr);
|
||||||
xfree(linebuf_vcol);
|
xfree(linebuf_vcol);
|
||||||
xfree(linebuf_scratch);
|
xfree(linebuf_scratch);
|
||||||
|
set_destroy(glyph, &glyph_cache);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// (Re)allocates a window grid if size changed while in ext_multigrid mode.
|
/// (Re)allocates a window grid if size changed while in ext_multigrid mode.
|
||||||
/// Updates size, offsets and handle for the grid regardless.
|
/// 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_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_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_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_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_get(T, U) map_get_##T##U
|
||||||
#define map_has(T, map, key) set_has(T, &(map)->set, key)
|
#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_ref(T, U) map_ref_##T##U
|
||||||
#define map_put_ref(T, U) map_put_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_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_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_get(T) map_get(T, ptr_t)
|
||||||
#define pmap_put(T) map_put(T, ptr_t)
|
#define pmap_put(T) map_put(T, ptr_t)
|
||||||
|
@ -1117,7 +1117,6 @@ void marktree_clear(MarkTree *b)
|
|||||||
b->root = NULL;
|
b->root = NULL;
|
||||||
}
|
}
|
||||||
map_destroy(uint64_t, b->id2node);
|
map_destroy(uint64_t, b->id2node);
|
||||||
*b->id2node = (PMap(uint64_t)) MAP_INIT;
|
|
||||||
b->n_keys = 0;
|
b->n_keys = 0;
|
||||||
assert(b->n_nodes == 0);
|
assert(b->n_nodes == 0);
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,12 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "nvim/api/extmark.h"
|
#include "nvim/api/extmark.h"
|
||||||
|
#include "nvim/api/private/helpers.h"
|
||||||
|
#include "nvim/api/ui.h"
|
||||||
#include "nvim/arglist.h"
|
#include "nvim/arglist.h"
|
||||||
#include "nvim/ascii_defs.h"
|
#include "nvim/ascii_defs.h"
|
||||||
#include "nvim/buffer_updates.h"
|
#include "nvim/buffer_updates.h"
|
||||||
|
#include "nvim/channel.h"
|
||||||
#include "nvim/context.h"
|
#include "nvim/context.h"
|
||||||
#include "nvim/decoration_provider.h"
|
#include "nvim/decoration_provider.h"
|
||||||
#include "nvim/drawline.h"
|
#include "nvim/drawline.h"
|
||||||
@ -23,14 +26,19 @@
|
|||||||
#include "nvim/insexpand.h"
|
#include "nvim/insexpand.h"
|
||||||
#include "nvim/lua/executor.h"
|
#include "nvim/lua/executor.h"
|
||||||
#include "nvim/main.h"
|
#include "nvim/main.h"
|
||||||
|
#include "nvim/map_defs.h"
|
||||||
#include "nvim/mapping.h"
|
#include "nvim/mapping.h"
|
||||||
#include "nvim/memfile.h"
|
#include "nvim/memfile.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/message.h"
|
#include "nvim/message.h"
|
||||||
#include "nvim/option_vars.h"
|
#include "nvim/option_vars.h"
|
||||||
|
#include "nvim/os/input.h"
|
||||||
#include "nvim/sign.h"
|
#include "nvim/sign.h"
|
||||||
#include "nvim/state_defs.h"
|
#include "nvim/state_defs.h"
|
||||||
|
#include "nvim/statusline.h"
|
||||||
#include "nvim/ui.h"
|
#include "nvim/ui.h"
|
||||||
|
#include "nvim/ui_client.h"
|
||||||
|
#include "nvim/ui_compositor.h"
|
||||||
#include "nvim/usercmd.h"
|
#include "nvim/usercmd.h"
|
||||||
#include "nvim/vim_defs.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/grid.h"
|
||||||
# include "nvim/mark.h"
|
# include "nvim/mark.h"
|
||||||
# include "nvim/msgpack_rpc/channel.h"
|
# include "nvim/msgpack_rpc/channel.h"
|
||||||
|
# include "nvim/msgpack_rpc/helpers.h"
|
||||||
# include "nvim/ops.h"
|
# include "nvim/ops.h"
|
||||||
# include "nvim/option.h"
|
# include "nvim/option.h"
|
||||||
# include "nvim/os/os.h"
|
# include "nvim/os/os.h"
|
||||||
@ -738,6 +747,7 @@ void free_all_mem(void)
|
|||||||
free_all_marks();
|
free_all_marks();
|
||||||
alist_clear(&global_alist);
|
alist_clear(&global_alist);
|
||||||
free_homedir();
|
free_homedir();
|
||||||
|
free_envmap();
|
||||||
free_users();
|
free_users();
|
||||||
free_search_patterns();
|
free_search_patterns();
|
||||||
free_old_sub();
|
free_old_sub();
|
||||||
@ -792,6 +802,7 @@ void free_all_mem(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel_free_all_mem();
|
||||||
eval_clear();
|
eval_clear();
|
||||||
api_extmark_free_all_mem();
|
api_extmark_free_all_mem();
|
||||||
ctx_free_all();
|
ctx_free_all();
|
||||||
@ -815,8 +826,14 @@ void free_all_mem(void)
|
|||||||
buf = bufref_valid(&bufref) ? nextbuf : firstbuf;
|
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!)
|
// free screenlines (can't display anything now!)
|
||||||
grid_free_all_mem();
|
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);
|
clear_hl_tables(false);
|
||||||
|
|
||||||
@ -824,10 +841,18 @@ void free_all_mem(void)
|
|||||||
|
|
||||||
decor_free_all_mem();
|
decor_free_all_mem();
|
||||||
drawline_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_free_all_mem();
|
||||||
|
ui_comp_free_all_mem();
|
||||||
nlua_free_all_mem();
|
nlua_free_all_mem();
|
||||||
rpc_free_all_mem();
|
rpc_free_all_mem();
|
||||||
|
msgpack_rpc_helpers_free_all_mem();
|
||||||
|
|
||||||
// should be last, in case earlier free functions deallocates arenas
|
// should be last, in case earlier free functions deallocates arenas
|
||||||
arena_free_reuse_blks();
|
arena_free_reuse_blks();
|
||||||
|
@ -751,6 +751,7 @@ const char *get_client_info(Channel *chan, const char *key)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EXITFREE
|
||||||
void rpc_free_all_mem(void)
|
void rpc_free_all_mem(void)
|
||||||
{
|
{
|
||||||
cstr_t key;
|
cstr_t key;
|
||||||
@ -758,4 +759,8 @@ void rpc_free_all_mem(void)
|
|||||||
xfree((void *)key);
|
xfree((void *)key);
|
||||||
});
|
});
|
||||||
set_destroy(cstr_t, &event_strings);
|
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);
|
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 {
|
typedef struct {
|
||||||
const msgpack_object *mobj;
|
const msgpack_object *mobj;
|
||||||
Object *aobj;
|
Object *aobj;
|
||||||
|
@ -583,6 +583,9 @@ void free_all_options(void)
|
|||||||
}
|
}
|
||||||
free_operatorfunc_option();
|
free_operatorfunc_option();
|
||||||
free_tagfunc_option();
|
free_tagfunc_option();
|
||||||
|
XFREE_CLEAR(fenc_default);
|
||||||
|
XFREE_CLEAR(p_term);
|
||||||
|
XFREE_CLEAR(p_ttytype);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -510,6 +510,17 @@ void free_homedir(void)
|
|||||||
xfree(homedir);
|
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
|
#endif
|
||||||
|
|
||||||
/// Call expand_env() and store the result in an allocated string.
|
/// 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);
|
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)
|
static void cursorhold_event(void **argv)
|
||||||
{
|
{
|
||||||
event_T event = State & MODE_INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD;
|
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);
|
free_ui_event_callback(event_cb);
|
||||||
})
|
})
|
||||||
map_destroy(uint32_t, &ui_event_cbs);
|
map_destroy(uint32_t, &ui_event_cbs);
|
||||||
|
|
||||||
|
multiqueue_free(resize_events);
|
||||||
}
|
}
|
||||||
#endif
|
#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,
|
tui_raw_line(tui, grid, row, startcol, endcol, clearcol, g->cur_attr, lineflags,
|
||||||
(const schar_T *)grid_line_buf_char, grid_line_buf_attr);
|
(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;
|
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)
|
void ui_comp_syn_init(void)
|
||||||
{
|
{
|
||||||
dbghl_normal = syn_check_group(S_LEN("RedrawDebugNormal"));
|
dbghl_normal = syn_check_group(S_LEN("RedrawDebugNormal"));
|
||||||
|
Loading…
Reference in New Issue
Block a user