anyone else seen increased cpu usage with clojure-lsp when rebasing etc?
I recall a while back clojure-lsp learned how to rescan the project when you e.g. switch branches.
For a while now (maybe a few weeks or so) what I've seen is that I'll do some trivial change (e.g. squash a bunch of wip commits into a single commit) and I'll notice my cpu usage goes through the roof as clojure-lsp starts to calculate something. I've tried to wait a while but usually I just close my project in emacs, which kill the lsp process.
I was wondering if anyone else has seen anything like this or if there's some diagnostics I could provide to debug this
I managed to look at the logs while this was happening at it was just thousands of lines of
025-08-04T08:53:14.622Z INFO [clojure-lsp.feature.diagnostics.built-in:301] - :internal/built-in-linters.different-aliases 0ms
2025-08-04T08:53:14.622Z INFO [clojure-lsp.feature.diagnostics.built-in:301] - :internal/built-in-linters.different-aliases 0ms
2025-08-04T08:53:14.622Z INFO [clojure-lsp.feature.diagnostics.built-in:304] - :internal/built-in-linters.cyclic-dependencies 0ms
2025-08-04T08:53:14.624Z INFO [clojure-lsp.feature.diagnostics.built-in:295] - :internal/built-in-linters.find-linter-ignore-comments 26ms
2025-08-04T08:53:14.632Z INFO [clojure-lsp.feature.diagnostics.built-in:289] - :internal/built-in-linters 5482ms
2025-08-04T08:53:14.632Z INFO [clojure-lsp.feature.diagnostics.built-in:304] - :internal/built-in-linters.cyclic-dependencies 0ms
2025-08-04T08:53:14.636Z INFO [clojure-lsp.feature.diagnostics.built-in:298] - :internal/built-in-linters.unused-public-vars 2441ms
2025-08-04T08:53:14.638Z INFO [clojure-lsp.feature.diagnostics.built-in:298] - :internal/built-in-linters.unused-public-vars 683ms
2025-08-04T08:53:14.639Z INFO [clojure-lsp.feature.diagnostics.built-in:289] - :internal/built-in-linters 2479ms
2025-08-04T08:53:14.642Z INFO [clojure-lsp.feature.diagnostics.built-in:289] - :internal/built-in-linters 705ms
2025-08-04T08:53:14.634Z INFO [clojure-lsp.dep-graph:280] - :internal/maintain-dep-graph 2ms
2025-08-04T08:53:14.643Z INFO [clojure-lsp.server:613] - :internal/analyze-file 25661ms
2025-08-04T08:53:14.643Z INFO [clojure-lsp.server:195] - :lsp/refresh-test-tree 0ms
2025-08-04T08:53:14.645Z INFO [clojure-lsp.feature.file-management:263] - :internal/uri-analyzed-by-clj-depend 0ms
2025-08-04T08:53:14.649Z INFO [clojure-lsp.dep-graph:280] - :internal/maintain-dep-graph 9ms
2025-08-04T08:53:14.652Z INFO [clojure-lsp.feature.diagnostics.built-in:298] - :internal/built-in-linters.unused-public-vars 3132ms
2025-08-04T08:53:14.659Z INFO [clojure-lsp.feature.diagnostics.built-in:289] - :internal/built-in-linters 3214ms
2025-08-04T08:53:14.661Z INFO [clojure-lsp.feature.diagnostics.built-in:295] - :internal/built-in-linters.find-linter-ignore-comments 42ms
2025-08-04T08:53:14.666Z INFO [clojure-lsp.dep-graph:280] - :internal/maintain-dep-graph 6ms
2025-08-04T08:53:14.669Z INFO [clojure-lsp.feature.diagnostics.built-in:304] - :internal/built-in-linters.cyclic-dependencies 0ms
2025-08-04T08:53:14.668Z INFO [clojure-lsp.server:132] - :lsp/publish-diagnostics 0ms
2025-08-04T08:53:14.672Z INFO [clojure-lsp.feature.diagnostics.built-in:304] - :internal/built-in-linters.cyclic-dependencies 0ms
2025-08-04T08:53:14.672Z INFO [clojure-lsp.feature.diagnostics.built-in:301] - :internal/built-in-linters.different-aliases 0ms
2025-08-04T08:53:14.674Z INFO [clojure-lsp.feature.diagnostics.built-in:295] - :internal/built-in-linters.find-linter-ignore-comments 2ms
2025-08-04T08:53:14.674Z INFO [clojure-lsp.feature.diagnostics.built-in:301] - :internal/built-in-linters.different-aliases 0ms
2025-08-04T08:53:14.677Z INFO [clojure-lsp.feature.diagnostics.built-in:304] - :internal/built-in-linters.cyclic-dependencies 0ms
2025-08-04T08:53:14.677Z INFO [clojure-lsp.feature.diagnostics.built-in:295] - :internal/built-in-linters.find-linter-ignore-comments 56ms
2025-08-04T08:53:14.678Z INFO [clojure-lsp.feature.diagnostics.built-in:289] - :internal/built-in-linters 2397ms
2025-08-04T08:53:14.681Z INFO [clojure-lsp.feature.diagnostics.built-in:295] - :internal/built-in-linters.find-linter-ignore-comments 8ms
2025-08-04T08:53:14.681Z INFO [clojure-lsp.feature.diagnostics.built-in:301] - :internal/built-in-linters.different-aliases 0ms
2025-08-04T08:53:14.683Z INFO [clojure-lsp.feature.diagnostics.built-in:295] - :internal/built-in-linters.find-linter-ignore-comments 11ms
2025-08-04T08:53:14.683Z INFO [clojure-lsp.kondo:174] - :internal/kondo-findings->analysis 0ms
2025-08-04T08:53:14.684Z INFO [clojure-lsp.feature.diagnostics.built-in:298] - :internal/built-in-linters.unused-public-vars 799ms
2025-08-04T08:53:14.694Z INFO [clojure-lsp.feature.diagnostics.built-in:289] - :internal/built-in-linters 902ms
2025-08-04T08:53:14.694Z INFO [clojure-lsp.feature.diagnostics.built-in:295] - :internal/built-in-linters.find-linter-ignore-comments 778ms
2025-08-04T08:53:14.697Z INFO [clojure-lsp.dep-graph:280] - :internal/maintain-dep-graph 3ms
2025-08-04T08:53:14.698Z INFO [clojure-lsp.dep-graph:280] - :internal/maintain-dep-graph 14ms
2025-08-04T08:53:14.685Z INFO [clojure-lsp.feature.diagnostics.built-in:295] - :internal/built-in-linters.find-linter-ignore-comments 69ms
2025-08-04T08:53:14.704Z INFO [clojure-lsp.feature.diagnostics.built-in:298] - :internal/built-in-linters.unused-public-vars 3211ms
2025-08-04T08:53:14.720Z INFO [clojure-lsp.feature.diagnostics.built-in:301] - :internal/built-in-linters.different-aliases 0ms
2025-08-04T08:53:14.720Z INFO [clojure-lsp.feature.diagnostics.built-in:304] - :internal/built-in-linters.cyclic-dependencies 0ms
2025-08-04T08:53:14.723Z INFO [clojure-lsp.feature.diagnostics.built-in:289] - :internal/built-in-linters 3251ms
2025-08-04T08:53:14.724Z INFO [clojure-lsp.feature.diagnostics.built-in:295] - :internal/built-in-linters.find-linter-ignore-comments 120ms
2025-08-04T08:53:14.724Z INFO [clojure-lsp.feature.diagnostics.built-in:304] - :internal/built-in-linters.cyclic-dependencies 0ms
2025-08-04T08:53:14.725Z INFO [clojure-lsp.dep-graph:280] - :internal/maintain-dep-graph 1ms
2025-08-04T08:53:14.725Z INFO [clojure-lsp.feature.file-management:153] - :reference-files/find 77ms
2025-08-04T08:53:14.725Z INFO [clojure-lsp.feature.file-management:151] - :internal/notify-references 78ms
2025-08-04T08:53:14.727Z INFO [clojure-lsp.feature.diagnostics.built-in:295] - :internal/built-in-linters.find-linter-ignore-comments 7ms
2025-08-04T08:53:14.731Z INFO [clojure-lsp.dep-graph:280] - :internal/maintain-dep-graph 53ms
2025-08-04T08:53:14.731Z INFO [clojure-lsp.feature.diagnostics.built-in:298] - :internal/built-in-linters.unused-public-vars 3271ms
2025-08-04T08:53:14.730Z INFO [clojure-lsp.feature.diagnostics.built-in:301] - :internal/built-in-linters.different-aliases 0ms
2025-08-04T08:53:14.736Z INFO [clojure-lsp.feature.diagnostics.built-in:298] - :internal/built-in-linters.unused-public-vars 1667ms
2025-08-04T08:53:14.731Z INFO [clojure-lsp.feature.diagnostics.built-in:298] - :internal/built-in-linters.unused-public-vars 1912ms
2025-08-04T08:53:14.741Z WARN [clojure-lsp.kondo:372] - [clj-kondo] No configs copied.
2025-08-04T08:53:14.743Z INFO [clojure-lsp.feature.diagnostics.built-in:295] - :internal/built-in-linters.find-linter-ignore-comments 16ms
2025-08-04T08:53:14.749Z INFO [clojure-lsp.feature.diagnostics.built-in:304] - :internal/built-in-linters.cyclic-dependencies 0ms
2025-08-04T08:53:14.750Z INFO [clojure-lsp.feature.diagnostics.built-in:298] - :internal/built-in-linters.unused-public-vars 3356ms
2025-08-04T08:53:14.751Z INFO [clojure-lsp.feature.diagnostics.built-in:289] - :internal/built-in-linters 4127ms
2025-08-04T08:53:14.753Z INFO [clojure-lsp.feature.diagnostics.built-in:289] - :internal/built-in-linters 1944ms
2025-08-04T08:53:14.753Z INFO [clojure-lsp.dep-graph:280] - :internal/maintain-dep-graph 2ms
2025-08-04T08:53:14.755Z INFO [clojure-lsp.feature.diagnostics.built-in:301] - :internal/built-in-linters.different-aliases 0ms
2025-08-04T08:53:14.756Z INFO [clojure-lsp.kondo:174] - :internal/kondo-findings->analysis 0ms
2025-08-04T08:53:14.756Z INFO [clojure-lsp.feature.file-management:259] - :internal/uri-analyzed-by-clj-kondo 112ms
2025-08-04T08:53:14.759Z INFO [clojure-lsp.dep-graph:280] - :internal/maintain-dep-graph 0ms
2025-08-04T08:53:14.767Z INFO [clojure-lsp.feature.diagnostics.built-in:304] - :internal/built-in-linters.cyclic-dependencies 0ms
2025-08-04T08:53:14.770Z INFO [clojure-lsp.feature.diagnostics.built-in:289] - :internal/built-in-linters 3409ms
2025-08-04T08:53:14.771Z INFO [clojure-lsp.feature.diagnostics.built-in:301] - :internal/built-in-linters.different-aliases 0ms
2025-08-04T08:53:14.773Z INFO [clojure-lsp.feature.diagnostics.built-in:295] - :internal/built-in-linters.find-linter-ignore-comments 11ms
2025-08-04T08:53:14.774Z INFO [clojure-lsp.feature.diagnostics.built-in:289] - :internal/built-in-linters 1761ms
2025-08-04T08:53:14.780Z INFO [clojure-lsp.dep-graph:280] - :internal/maintain-dep-graph 28msI have recently switched to Neovim from VSCode, mainly to avoid the lagginess that seems to plague VSCode. However, I can't seem to avoid the clojure-lsp lag - it's even noticeably slower (or perhaps I just see it better) - I also get an occasional time out. However, I don't see a CPU spike or anything like that that would explain the error. Any similar issues by neovim users?
I've been using Neovim (AstroNvim) with Clojure LSP & Conjure for the last couple of years, on two different commercial projects. I haven't experienced any performance issues with Clojure LSP or Neovim's LSP client (Neovim 0.9 / 0.10 /0.11). I do have 32Gb on Linux / MacOSX machines. Note: I've also run Clojure LSP on an android tablet via Termux and the jar version for Clojure LSP and it worked well.
have you tried the latest nightly build? there might be an improvement in there
I was just reading through that. Indeed, clojure-lsp is the most memory intensive program in my list right now!
how much memory does your system have
I have an M1 Macbook Air with 16GB.
I have one too (one of my systems)
Right now I see clojure-lsp at 6.53 GB
I will check how to install nightly builds with use in Neovim
6gb sounds too much. About the lag, I never heard issues like that, after started server is fast. Maybe it's a nvim thing like emacs has lsp-idle-time which is the time to process server new messages
I did a fresh restart of everything incl. download the nightly build mentioned above. So far everything is very very fast, but I will check to see how it goes through the course of the day.
After a day of working, I see the memory usage at 3.85gb
The initial memory at startup was around 2gb
I have these java processes which run clojure-lsp. the 7gb one is metabase, one of the biggest OSS clojure projects I know
I don't think it can be clj-kondo anymore though since there's nothing being kept in memory anymore (hopefully) after run! is finished
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
ClojureScript 305 6192 2237 69649
Clojure 358 9626 3965 67046
ClojureC 21 340 168 2026looks like a pretty normal project
Yep, nothing huge.
it could be that clojure-lsp is also using a cache (using memoize or other) with collections as keys. this is what messed up clj-kondo's memory usage
The interesting thing is that all that memory is swapped to disk. The "real memory" used is only 40MB.
ah, it could be that it's just keeping files in the memory cache, the OS does that to keep things fast
huh
no, maybe your machine is just swapping because of memory shortage
Yes, it's definitely swapping out.
is memory pressure yellow in your activity tab?
Does it even have any other color? š
hehe. mine is also constantly yellow (on my m1). I opted for more memory in my newer machine
is it still slow though? or managable?
neovim became usable again. I've also killed an ollama server I had running in the background. AI so far has been only a drag š
The LSP is snappy - it feels like I'm not waiting on it at all.
if it feels fast, that's the most important thing I guess
if lsp has a memory leak, should manifest itself after using it for a longer time and running larger and larger. should be detectable via an hprof file
this might also help: https://www.graalvm.org/latest/reference-manual/native-image/guides/create-heap-dump/
I'll clock out for the day and resume tomorrow, let's see how another full day feels like.
oh I guess you should compile the native image with --enable-monitoring=heapdump,jvmstat to be able to get an hprof file
might as well run a jvm when testing for this
to be honest I'm too close to my vacation (Friday, yay!) to test for this. It feels like it could be tested synthetically somehow by running a server and sending 10 commands per second for a period of a hew hours...
Ollama serve affects a lot my machine memory BTW. And yes, clojure-lsp has a atom in memory for all analysis, but I don't think it should be a problem unless it's a metabase project with thousands of analysis
You can always tune and disable keywords or other features analysis although not ideal
Speaking of, in Calva/VSCode, I could get references to keywords etc, but in neovim it seems not. I guess Calva overrides some configuration properties? I will have to revisit.
Sounds like you are using a outdated clojure-lsp? Keyword References should work all the same for any client
In the end it's just LSP references feature
Iām using the nightly version as of this morning
What I used to able to do, was in big EDN file, I was able to go to definition on plain keywords and it would take me to the place where that keyword appears as a key. Not sure if that was a VACode heuristic though.
maybe, clojure-lsp supports find-definition of keywords only when it's a reg-fx or similar, not only map keys
is it possible to constrain lsp-find-references to a specific set of namespaces somehow?
pretty sure the path regex stuff isn't working as described, @ericdallo š
should i file an issue?
why do you use multiple of the same strings on source-paths-ignore-regex and why do you use a trailing /?
(not that is probably matters)
i don't:
{:clean {:automatically-after-ns-refactor true
:ns-inner-blocks-indentation :same-line
:ns-import-classes-indentation :same-line}
:cljfmt-config-path ".cljfmt.edn"
:source-paths-ignore-regex ["src/cognician/chat/"
"src/cognician/c3_model"]
:paths-ignore-regex ["src/cognician/chat/"
"src/cognician/c3_model"]}and, the trailing slash is so that chat_c4 is not filtered out
ok, I see something different in your screenshot
yeah the duplicates are in the lsp-clojure-server-info output, but not in the config i maintain
weird
I'm using this script to run clojure-lsp locally:
#!/usr/bin/env bash
# override project config:
export CLJ_KONDO_EXTRA_CONFIG_DIR=~/.config/clj-kondo
clj -Sdeps '{:aliases
{:lsp
{:replace-paths []
:replace-deps
{org.clojure/clojure {:mvn/version "1.11.1"}
clj-kondo/clj-kondo {:local/root "/Users/borkdude/dev/clj-kondo"}
clojure-lsp/clojure-lsp {:local/root "/Users/borkdude/dev/clojure-lsp/cli"}
cider/cider-nrepl {:mvn/version "0.28.6"}}}}}' \
-M:lsp -m clojure-lsp.main "$@"
I use this to always have my dev version of clj-kondo active, but you could also try this to debug the source-paths regex thingusually i'd just tough it out (i have been for years), but in this situ i'd really value the ability to filter like this
ok ty!
in your case you can leave out clj-kondo and just let clojure-lsp pick clj-kondo
I don't remember why I have the env var at the top though
but you get the gist
i do, thanks borkers!
currently not
why would you do so @robert-stuttaford?
210,000 loc monorepo š
reworking a part of the code some times involves working through a set of find-references. being able to limit that to a src sub-path reduces friction
you can configure clojure-lsp to ignore some paths for analysis, then it should exclude all features including references
that might help, thank you!
:paths-ignore-regex or :source-paths-ignore-regex
https://clojure-lsp.io/settings/#all-settings
i have two paths src/cognician/chat/* and src/cognician/chat_c4/*. i want the first one ignored but not the second. my settings, which don't seem to work after a restart of emacs (in .lsp/config.edn; .lsp is a sibling of src):
:source-paths-ignore-regex ["src/cognician/chat/.*"]
i guess i need to clear caches š
trying that now...
naw it's still listing stuff from that folder
the source-paths is kinda of tricky, try checking clojure-lsp server logs about the source-paths using when starting