jola
A question was asked here whether releases use less memory, so checked in a project I’m working on and I was surprised to see almost twice the memory use for the same code. To make sure it wasn’t just my project, I tried with a plain Phoenix app and only the minimal steps to get releases started. This is what I did if you want to reproduce:
mix phx.new hello --no-webpack --no-html --no-ecto
# added {:distillery, "~> 2.0"} to mix.exs
cd hello
mix deps.get
MIX_ENV=prod mix release
Then to compare the memory use I relied on :erlang.memory/0. First using plain mix run in iex.
MIX_ENV=prod iex -S mix run
iex(1)> :erlang.memory
[
total: 31407808,
processes: 7082192,
processes_used: 7063440,
system: 24325616,
atom: 512625,
atom_used: 504423,
binary: 97440,
code: 10298466,
ets: 929712
]
and then starting the release in the equivalent console
_build/prod/rel/hello/bin/hello console
iex(hello@127.0.0.1)1> :erlang.memory
[
total: 55362432,
processes: 14649704,
processes_used: 14363384,
system: 40712728,
atom: 984241,
atom_used: 961617,
binary: 174464,
code: 21349495,
ets: 2029176
]
Total reported memory use went from 31MB to 55MB. And you see increases across the board. In my personal project the increase was even more significant, going from 45MB to 90MB.
One thing I guess could be related is that I believe releases preload all code while mix will load modules on demand. But does that really account for the whole difference?
I also want to add a disclaimer: I’m still using releases and I don’t find the memory used to be unreasonable. This is just curiosity!
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










Showing Posts 1 to 7- Show Best Posts
- Show All Posts (oldest first)
- Show All Posts (newest first)
michalmuskala
I think the code loading part will be the major difference - more code means more atoms, more binaries (from literals in those modules) and more ets usage (since information which modules are loaded is held in an ets table by the
code_serverprocess). Additionally there might be some more system-level services running like SASL or the release handlers, which could account for the extra process size. Have you tried comparing the outputs ofProcess.list()on both systems? That could shed some more light on it. Similarly for ets tables you could investigate with:ets.info.rvirding
Check to see which applications have been loaded, there may be more in the release. Also check which applications have been started. IIRC correctly the release will start all applications at start up time.
rodrigues
I’ve had similar numbers here, @jola, using your steps.
Following @rvirding suggestion, I’ve ran this code in each:
saslhex,inetsI guess
saslis the likely culprit?UPDATE: sasl start not relevant to memory. I’ve checked also the loaded applications, and it’s the same as started applications. That’s intriguing
tristan
Your release is likely starting in embedded mode while
mix runis interactive mode. Embedded mode will load all beam modules on start up instead of only when they are used.See System Principles — Erlang System Documentation v29.0.2
rodrigues
Indeed, using
:code.all_loaded(), I saw the release has663modules loaded in it that were not loaded in mix run, while the contrary is25.jola
I tried comparing named processes between the app started through mix and the release and came up with this
which seems to show the same differences that @rodrigues found comparing the running applications. Put the output and the code I ran here.
I wonder what the memory use would be when running with mix if you force-load all the modules.
rodrigues
passing
--preload-modulestomix runseems to do the job, actually it loads133modules more than release, while the modules below are loaded by release but not loaded in mix run, even with preload:It does increase memory significantly, but release still has more (gist with output).