denna
In a project I had a genserver that holds its local state. This state isnt exceptionally big but part of it was a list of 1000 ids that is a few times per second updated( items removed or added). The effect of this was that every few seconds the process appeared stuck ( i guess something related to garbage collection ). This problem got resolved by putting the list into a separate process.
Now I wonder what could be a general rule for processes. When should i separate a part of a state into a separate state?
If I add a item to the beginning of a list inside a map does this imply the complete map is copied?
Trending in Questions
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
Documentation
While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
Hello,
I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind.
However, when I launch mix phx.server, I get an error...
New
Hi everyone,
I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding.
I sta...
New
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
I’m working on a small exercise involving update_in/3, and I came up with this solution:
data = %{
name: "Periodic Table",
category:...
New
I’ve got trouble wrapping my head around the order in which functions are called in this snippet (from Phoenix’s authentication):
toke...
New
Other Trending Topics
Edit: 2026 May 15 - This post is archived.
Mob is alive!!
Main docs: mob v0.7.11 — Documentation
A bit of explanation for the slightly c...
New
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hobbes is a low-level distributed database for the Elixir programming language.
Hobbes provides a simple, safe, and scalable storage lay...
New
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
A little off-topic, but I feel like people here have a good head on their shoulders.
I used to be quite good at making software. Was luc...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ai
- #ecto-query
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #metaprogramming
- #hex











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
hauleth
Maybe you should have used ETS table instead of list? If there are random updates it can make it slower even further.
lud
If the order of IDs in you list doesn’t matter, you can keep the list sorted to get better performance when inserting or removing IDs.
Or using a
MapSetcould be better too. But in any case 1000 ids “a few times per second” is small and you should not notice a GC pause for that.benwilson512
As @hauleth notes,
:etsmay be the right call here. It has the further perk of not creating garbage collector pressure, since its items are stored in its own managed memory space instead of within the process memory.derek-zhou
When it get slow. However, as other has noted, what you are doing should not be slow; and even if it does get slow, there is other ways to make it faster, such as ets.
denna
I am sure I am have a GC pause for something related to this list. 1) Because I could tweek it a little bit by changing the GC parameters of the GenServer. 2) Because the separation of the list into another process made everything smooth.
But you are right its not the list itself. to be a bit more precise its a list of unordered integers that provide available unique ids (within a specified range).
Am I right that a list updated with [head|tail] triggers little memory movement (sorry i don’t know the right term)?
Does updating a list within a map create significantly more “memory movement”, so that the GC has to work?
For example does a change in a implies that b has to be copied?
lucaong
No, the value associated to
bshould not be copied if you changea. Rather, a new map that references the samebshould be created. The details probably depend on the size of the map (I guess bigger maps are implemented as HAMT, smaller ones possibly not), but in any casebshould not be copied if something else in the map changes: the implementation will generally try to reference as much as possible of the old immutable data structure.I suspect there is something more to your case, could you maybe share some code?
lud
I ran a quick benchmark based on a list of 1000 ids. When adding 500 existing ids and 500 new ids, then removing 500 existing and 500 not existing, ETS was the fastest.
Adding and removing 200 IDs, MapSet was faster (still on a 1000 IDs list at start).
My quick and dirty unique list implementation was the slowest in any case.
But ETS comes with its own new problems because it is like a mutable array. Now, that should not be a problem since you use another process currently, so you already have a “kind of mutable” state. But if you need to do a lot of things locally with those IDs, don’t use ETS if it is impractical I guess.
But I agree, show us some code!
krasenyp
ETS is a nice solution to your problem. One consideration, most guides show an ETS table “managed” by a GenServer but this is suboptimal. ETS allows concurrent access and a GenServer in front of it limits the concurrency. Just create a table, maybe in your Application, and access it through it’s name from a module containing only functions.
benwilson512
I think you’re confusing the practice of having a specific process that owns the
:etstable with the practice of serializing access to that table through the genserver. The two are orthogonal. You can setup a named table with read / write concurrency that is accessed directly, but still is owned by a supervised process. It is generally a best practice to put:etstables under such managed processes because it allows them to be started / stopped / restarted effectively within your application’s supervision tree.bjunc
It should probably be said that an entire book chapter could be dedicated to these situations (I believe there are a few in existence!). I’d maybe go as far as to say it’s one of the main quirks with immutable data, since you can find yourself copying the data over and over instead of what is a simple pointer update in mutable languages.
Also, a thousand IDs should not cause what you are describing; which makes me think you are replicating the data. If the ETS option doesn’t solve your problem, I’ve picked up a few tricks when dealing with this type of scenario; which might be applicable for you:
you can inspect the process’ memory usage using Observer. Runaway increases in memory may be a sign that old data is not being cleaned up as you update the ID list.
if you’re processing the IDs each in a dedicated process, you can “monitor” the process, listen for the
:DOWNmessage, and then force garbage collection (:erlang.garbage_collect()). Not ideal, but it can work. You can target particular processes as well (eg. parent process).state (memory) can come along for the ride when using Task.Supervisor with anonymous functions. Here’s a nice explanation (not a bug). Short answer, MFA is preferred. If you’re doing any supervised processing in a loop, you may be inadvertently passing a lot of data around (locking it up).