4 ms·
Try doing C with a garbage collector ... it's very liberating. Do `#include <gc.h>` then just use `GC_malloc()` instead of `malloc()` and never free. And add `
by brucehoult 2y ago
Try doing C with a garbage collector ... it's very liberating.
Do `#include <gc.h>` then just use `GC_malloc()` instead of `malloc()` and never free. And add `-lgc` to linking. It's already there on most systems these days, lots of things use it.
You can add some efficiency by `GC_free()` in cases where you're really really sure, but it's entirely optional, and adds a lot of danger. Using `GC_malloc_atomic()` also adds efficiency, especially for large objects, if you know for sure there will be no pointers in that object (e.g. a string, buffer, image etc).
There are weak pointers if you need them. And you can add finalizers for those rare cases where you need to close a file or network connection or something when an object is GCd, rather than knowing programmatically when to do it.
But simply using `GC_malloc()` instead of `malloc()` gets you a long long way.
You can also build Boehm GC as a full transparent `malloc()` replacement, and replacing `operator new()` in C++ too.
- dlisboa 2y agoWhich GC is that you’re using in these examples?
- School-Cotton 2y agoI'm not OP but the most popular C GC is Boehm's: https://www.hboehm.info/gc/ https://www.hboehm.info/gc/
- kokada 2y agoI think one of the nice things about C is that since the language was not designed to abstract e.g.: heap is that it is really easy to replace manual memory management with GC or any other approach to manage memory, because most APIs expects to be called with `malloc()` when heap allocation is needed. I think the only other language that has a similar property is Zig.
- irq-1 2y agoOdin has this too: > Odin is a manual memory management based language. This means that Odin programmers must manage their own memory, allocations, and tracking. To aid with memory management, Odin has huge support for custom allocators, especially through the implicit context system. https://odin-lang.org/docs/overview/#implicit-context-system https://odin-lang.org/docs/overview/#implicit-context-system
- kokada 2y agoInteresting that I was thinking of a language that combined Zig and Scala to allocate memory using implicits and this looks exactly what I was thinking. Not that I actually think this is a good idea (I think the explicitly style of Zig is better), but it is an idea nonetheless.
- 59nadir 2y agoA lot of our Odin procs take an allocator as a required argument specifically so they force you to choose one at the call site, because yes, often you want it to be explicit.
- kokada 2y agoI am thinking now a language that had the default allocator be a GC, but you could change it to something else using implicits/context and this is enfoced everywhere (e.g.: there is no way to allocate memory "from magic", you need to call the allocator, even if it is from context). At least thinking in Scala as a base syntax here, it would mean: def foo(name: String)(implicit allocator: MemoryAllocator): StringBuf = { val buf = allocator.new(100, String) buf.append("Hello ") buf.append(name) buf } println(foo("John")) // implicit allocator from context, default to GC, no need to free implicit val allocator: MemoryAllocator = allocators.NewAllocator() println(foo("Alice")) // another implicit allocator, but now using the manual allocator instead of GC defer allocator.free() val explicitAllocator = allocators.NewArenaAllocator() foo("Marie")(explicitAllocator) // explicit allocator only for this call defer explicitAllocator.free() I don't think there is any language right now that has this focus, since Odin seems to be focused in manual allocations.
- enriquto 2y ago> Try doing C with a garbage collector ... it's very liberating. > Do `#include <gc.h>` then just use `GC_malloc()` instead of `malloc()` and never free. Even more liberating (and dangerous!): do not even malloc, just use variable length-arrays: void f(float *y, float *x, int n) { float t[n]; // temporary array, destroyed at the end of scope ... } This style forces you to alloc the memory at the outermost scope where it is visible, which is a nice thing in itself (even if you use malloc).
- kqr 2y agoAt first I really liked this idea, but then I realised the size of stack frames is quite limited, isn't it? So this would work for small data but perhaps not big data.
- enriquto 2y agoIn theory, this is a compiler implementation detail. The compiler may chose to put large stacks in the heap, or to not even use a stack/heap system at all. The semantics of the language are independent of that. In practice, stack sizes used to be quite limited and system-dependent. A modern linux system will give you several megabites of stack by default (128MB in my case, just checked in my linux mint 22 wilma). You can check it using "ulimit -all", and you can change it for your child processes using "ulimit -s SIZE_IN_KB". This is useful for your personal usage, but may pose problems when distributing your program, as you'll need to set the environment where your program runs, which may be difficult or impossible. There's no ergonomical way to do that from inside your C program, that I know of.
- dzdt 2y agoIts a giant peeve of mine that automatic memory management, in the C language sense of the resource being freed at the end of its lexical scope, is tied to the allocation being on the machine stack which in practice may have incredibly limited size. Gar! Why!?
- 2y ago
- DeathArrow 2y ago>Try doing C with a garbage collector ... it's very liberating. Doing that means that I lose some speed and I will have to wait for GC collection. Then why shouldn't I use C# which is more productive and has libraries and frameworks that comes with batteries included that help me build functionality fast. I thought that one of the main points of using C is speed.
- brucehoult 2y agoEvery time I've tried it, adding GC to a C program makes it faster. It will increase the RAM usage by a bit, and exactly when pauses happen is less predictable (unless you explicitly trigger a GC in e.g. your main loop), and possibly individual pauses larger, but overall program execution time -- throughput -- increases. Malloc() and free() aren't free, and in particular free() does a lot more bookkeeping and takes more time than people realise.
- hexo 2y agoC# has disgusting code style. IWillNotReadCode where variable or (and thats even worse) function/method names LookLikeThis.