I’m not sure if Crystal is particularly memory efficient.
Sure, Crystal programs certainly use way less memory than other popular alternatives as you mentioned. But I think ther is some bias. When you consider a simple webapp bloating 200mb memory as acceptable, any significantly smaller memory consumption appears unrealisticly low.
@straight-shoota I swear, if there is such a thing as genetic predisposition for diplomacy, you have that.
I feel the need to translate that to plain language: NodeJS is an incredible resource hog (not just memory, also disk space, performance etc.). Comparing Crystal to that is like comparing a Tiger to a geriatric Gnu.
@straight-shoota , since someone discuss on this, i have one more question.
i read done all our document, references, but, none of them mention GC, sure i know we are use
bdwgc, but, i guess someone still want to know how it works.(not need too detail, but, understood a little is better), and more, if there is a threshold, which we should avoid exceed if we don’t want apply memory in heap …
It’s not just the node example the benchmarks against Julia also showed a huge memory difference. Think in general Crystal is as fast as C & as light as air.
You’re correct, we’re missing documentation in this regard. Quite frankly, I think it’s very hard to come up with something meaningful and succinct on the topic: most users are fine knowing someone will collect their trash, and advanced users needs more than just the basics. So far, bdwgc’s documentation is the best we have.
I think that partially the reason is also the std-lib and ecosystem design. Is not something of the language. Using IO as much as possible, encoding/decoding without needing the whole document in memory, avoiding short living heap allocations; are all things that contribute to the low memory footprint.
Without falling into early optimization is good to keep things that way, or at least have API that would not go against it.
This is a huge part of it. I really like that methods like to_json and to_s are all implemented in terms of the overload that takes an IO instance. It enables a lot of fantastic abstractions and lets you be flexible on which tradeoffs you make — you can do the easy thing (just return the string) just to get a feature out the door but you can also do the memory-efficient thing (write directly to a socket/file/whatever) when you need to conserve memory and the code isn’t that different.
When I discovered that even ECR does this, such that <%= value %> calls value.to_s(io), it made it really easy to do things like view components or other intermediate objects that can serialize to the output format, such as <%= ProductPage.new(product) %>.
Having these patterns in the stdlib influences the rest of the ecosystem. The reduced memory usage is one of the biggest reasons that Armature sends data out to the client ASAP rather than buffering the complete response body in memory before sending it. That way you can, for example, transform over half a million database rows into 286MB of JSON while using only 3MB of RAM. You almost certainly wouldn’t do that in a real app, but the fact that Crystal makes it so easy to be that memory-efficient even in such a pathological case (this was all it took) is amazing. Go and Rust could never.