> In other words, you may treat the operating system as “the ultimate garbage collector”—freeing memory when it is unnecessary will simply waste both your and the user’s time, and lead to code complexity and bugs that would otherwise not exist. Unfortunately, many popular programming education resources teach that cleanup code is always necessary. This is false. I disagree. One, I think the set of C code where both "…
I use arenas for HTTP request handlers. The JSON built or parsed is only going to be around for the lifetime of the request. It's much simpler and faster to use an arena than to do reference counting wrapped around malloc/free. Here's an example where in a commit I swapped in an arena: https://github.com/williamcotton/express-c/commit/4ae53f38e3...
Untangling Lifetimes: The Arena Allocator
51–60 of 94 posts
Re: Untangling Lifetimes: The Arena Allocator
#52The author should take another look at RIIA. The first big difference is that it works with non-memory resources too, for example open/close for files. The second is that it makes heap allocated data feel a lot like stack allocated data, since the resources are ultimately owned by variables on the stack. With “move semantics” resources can be passed as arguments and returned by functions too, so the example of lifeti…
Could someone please explain the usefulness of RAII? As I understand it, RAII refers to the initialization semantics of certain languages, most famously C++. If I remember correctly, it effectively states that variable declarations amount to reserving memory resources and nothing else; memory is not zeroed, for instance. My question is: what makes this so useful? Looking at wikipedia, the focus seems to be on lifetim…
Re: Untangling Lifetimes: The Arena Allocator
#53Earlier quoted context omitted.
IMHO the problem with C++ style RIIA is that it's not just about calling cleanup code at the end of a scope (this would be fine, really), but the 'rat's tail' that's attached to RAII for dynamic memory management: you also need the compiler to be able to invoke user-provided code for 'copy' and 'move' operations (or better named: deep- and flat-copy), you need different reference types to define ownership details (e.…
> (or better named: deep- and flat-copy) That's worse naming, not better! In particular, a copy does not change the thing it copies - but a C++ move does change the thing it moves from.
Re: Untangling Lifetimes: The Arena Allocator
#54The author should take another look at RIIA. The first big difference is that it works with non-memory resources too, for example open/close for files. The second is that it makes heap allocated data feel a lot like stack allocated data, since the resources are ultimately owned by variables on the stack. With “move semantics” resources can be passed as arguments and returned by functions too, so the example of lifeti…
Could someone please explain the usefulness of RAII? As I understand it, RAII refers to the initialization semantics of certain languages, most famously C++. If I remember correctly, it effectively states that variable declarations amount to reserving memory resources and nothing else; memory is not zeroed, for instance. My question is: what makes this so useful? Looking at wikipedia, the focus seems to be on lifetim…
It's not about initialization. It's about cleanup. The initialization aspect of RAII is incidental to its main purpose/use -- perhaps essential to it too, but not so essential that initialization becomes more the essence of RAII than cleanup.
It's really a C++ specific form of Lisp's unwind-protect.
Re: Untangling Lifetimes: The Arena Allocator
#55The author should take another look at RIIA. The first big difference is that it works with non-memory resources too, for example open/close for files. The second is that it makes heap allocated data feel a lot like stack allocated data, since the resources are ultimately owned by variables on the stack. With “move semantics” resources can be passed as arguments and returned by functions too, so the example of lifeti…
Could someone please explain the usefulness of RAII? As I understand it, RAII refers to the initialization semantics of certain languages, most famously C++. If I remember correctly, it effectively states that variable declarations amount to reserving memory resources and nothing else; memory is not zeroed, for instance. My question is: what makes this so useful? Looking at wikipedia, the focus seems to be on lifetim…
Not really. The idea is that any resource lifecycle management should be tied to the lifecycle of an object, therefore removing a whole class of problems. For example, when you open a file handle, the "open" operation should be tied to a class constructor, and the corresponding cleanup to the destructor. If you lock a mutex, that operation should be handled by a constructor, and the release by a destructor, so that you never forget to do the cleanup.
> My question is: what makes this so useful? Looking at wikipedia, the focus seems to be on lifetime guarantees, but I'm having trouble understanding how these are useful in practice.
I think Wikipedia should have an example of the things that RAII makes you avoid. Compare these two designs
class Config {
Config() { this->file = nullptr; }
void load(const std::string& path) { this->file = open(path); }
void close() { this->file->close(); }
versus class Config {
Config(const std::string& path) { this->file = open(path); }
~Config() { this->file->close(); }
The first design makes it easy to forget calling close() before releasing the object, or maybe writing a destructor that does a double free if close() had already been called... The second design is clear, and also safe to use around exceptions.As for the comparison with another language... I don't know enough about Go, but RAII is present in a lot of object oriented languages. For example, in Python, opening a file creates a "file" object with the resource (the file handle) already allocated, and when that object refcount goes to zero, the underlying handle is released. However, because in modern languages all the "resource management" is usually done in standard libraries and memory allocation isn't done manually, programmers of those won't really hear about RAII, because all that is managed already in the standard libraries.
Re: Untangling Lifetimes: The Arena Allocator
#56Earlier quoted context omitted.
It's a C++ myth that files and memory are the same problem, in reality files are an easier problem, cf java.
cf Java? Both in it and c# forgetting to close handles has been one of the most common mistakes I've seen. It pretty much never happens on c++.
Re: Untangling Lifetimes: The Arena Allocator
#57Earlier quoted context omitted.
> (or better named: deep- and flat-copy) That's worse naming, not better! In particular, a copy does not change the thing it copies - but a C++ move does change the thing it moves from.
Ok "flat-copy-with-src-invalidation". Somehow "move" makes it sound more efficient than copying a C struct, but it's actually the same thing (for POD structs), for non-POD it's even slightly more expensive because you need to fix up the source.
> "flat-copy-with-src-invalidation".
That's not what a move is in C++, at all. I wish we got destructive moves in C++, but we didn't (and I understand why..)
> for non-POD it's even slightly more expensive because you need to fix up the source.
This is just false.
Re: Untangling Lifetimes: The Arena Allocator
#58> the implementation simply reserves the address range in your virtual address space (e.g. by using VirtualAlloc on Windows). Does anyone know what would be the alternatives to VirtualAlloc on other platforms?
On Linux and other UNIX-like operating systems, that would be mmap with the MAP_ANONYMOUS flag.
The big question about all that is when this memory is actually being released back to the OS, because by default it isn't really. That also means you can trigger OOM faults despite the process having free memory even (which the OS sees differently).
Re: Untangling Lifetimes: The Arena Allocator
#59Earlier quoted context omitted.
Of course, it's still manual memory and pointer management after all. You could manually assign a pointer to 0xDEADBEEF if you want, or you could tell the arena to pop data that you are still using. The point is not perfection, it is simplicity and mapping tools to requirements.
Maybe I'm not understanding the point of the article then. It starts out as a polemical rant against the suggestion to use safer languages, and I guess I expected it to culminate in something more profound wrt safety. I use managed memory languages so I'm sure there's stuff I'm missing.
All of my formal instruction in C never mentioned this middle ground and it took both trial and error and working experience to learn about memory arenas.
Also, I’m convinced that evangelizing Rust memory safety has probably done more harm than good because to outsiders it is being made to seem like anything done in C is wrong and stupid and therefore no one should pay any attention to anything that has ever been written in C.
One of my worries before I start working in Rust is that I won’t be able to use my knowledge of resource management in C. That’s not the case at all but it takes having to filter through flame wars to figure things out!
Re: Untangling Lifetimes: The Arena Allocator
#60Earlier quoted context omitted.
It's a C++ myth that files and memory are the same problem, in reality files are an easier problem, cf java.
No, C++ has the idea that the same solution can be used for all resource management: file handles, memory, sockets, database cursors or connections, you name it. And it works. Resource life management is not a problem that Java handles with grace...