diff options
-rw-r--r-- | src/nvim/buffer.c | 6 | ||||
-rw-r--r-- | src/nvim/window.c | 37 | ||||
-rw-r--r-- | test/functional/legacy/memory_usage_spec.lua | 32 |
3 files changed, 68 insertions, 7 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 0b72dd1885..f1f32076bf 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -840,11 +840,7 @@ static void clear_wininfo(buf_T *buf) while (buf->b_wininfo != NULL) { wip = buf->b_wininfo; buf->b_wininfo = wip->wi_next; - if (wip->wi_optset) { - clear_winopt(&wip->wi_opt); - deleteFoldRecurse(buf, &wip->wi_folds); - } - xfree(wip); + free_wininfo(wip, buf); } } diff --git a/src/nvim/window.c b/src/nvim/window.c index aea60fe24c..d051e8e467 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4597,6 +4597,18 @@ static win_T *win_alloc(win_T *after, int hidden) } +// Free one wininfo_T. +void +free_wininfo(wininfo_T *wip, buf_T *bp) +{ + if (wip->wi_optset) { + clear_winopt(&wip->wi_opt); + deleteFoldRecurse(bp, &wip->wi_folds); + } + xfree(wip); +} + + /* * Remove window 'wp' from the window list and free the structure. */ @@ -4647,9 +4659,30 @@ win_free ( /* Remove the window from the b_wininfo lists, it may happen that the * freed memory is re-used for another window. */ FOR_ALL_BUFFERS(buf) { - for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next) - if (wip->wi_win == wp) + for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next) { + if (wip->wi_win == wp) { + wininfo_T *wip2; + + // If there already is an entry with "wi_win" set to NULL it + // must be removed, it would never be used. + for (wip2 = buf->b_wininfo; wip2 != NULL; wip2 = wip2->wi_next) { + if (wip2->wi_win == NULL) { + if (wip2->wi_next != NULL) { + wip2->wi_next->wi_prev = wip2->wi_prev; + } + if (wip2->wi_prev == NULL) { + buf->b_wininfo = wip2->wi_next; + } else { + wip2->wi_prev->wi_next = wip2->wi_next; + } + free_wininfo(wip2, buf); + break; + } + } + wip->wi_win = NULL; + } + } } clear_matches(wp); diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua index 97ac96804e..0f2d77093a 100644 --- a/test/functional/legacy/memory_usage_spec.lua +++ b/test/functional/legacy/memory_usage_spec.lua @@ -166,4 +166,36 @@ describe('memory usage', function() check_result({before=before, after=after, last=last}, pcall(ok, last.last < upper)) end) + + it('releases memory when closing windows when folds exist', function() + local pid = eval('getpid()') + source([[ + new + " Insert lines + call nvim_buf_set_lines(0, 0, 0, v:false, repeat([''], 999)) + " Create folds + normal! gg + for _ in range(500) + normal! zfjj + endfor + ]]) + poke_eventloop() + local before = monitor_memory_usage(pid) + source([[ + " Split and close window multiple times + for _ in range(1000) + split + close + endfor + ]]) + poke_eventloop() + local after = monitor_memory_usage(pid) + source('bwipe!') + poke_eventloop() + -- Allow for an increase of 5% in memory usage, which accommodates minor fluctuation, + -- but is small enough that if memory were not released (prior to PR #14884), the test + -- would fail. + local upper = before.last * 1.05 + check_result({before=before, after=after}, pcall(ok, after.last <= upper)) + end) end) |