Hacker News new | ask | show | jobs
by alexvitkov 523 days ago
> Otherwise, one would just declare a structure member of the class from which one would inherit in the OOP style and a virtual function table pointer, and one could write an identical program with the OOP program, but in a much more verbose way.

No, you don't have to do that. Once you start thinking about memory and manually managing it, it you'll figure out there's simpler, better ways to structure your program, rather than having a deep class hierarchy with a gazillion heap-allocated objects, each with distinct lifetime, all pointing at each other.

Here's a trivial example. Say you're writing a JSON parser - if you approach it with an OOP mindset, you would probably make a JSONValue class, maybe subclass it with JSONNumber/String/Object/Array. You would walk over the input string and heap allocate JSONValues as you go. The problems with this are:

    1. Each allocation can be very slow as it can enter the kernel
    2. Each allocation is a possible failure point, so the number of failure points scales linearly with input size.
    3. When you free the structure, you must walk over the entire tree and free each obejct one by one.
    4. The output of this function is suboptimal as the memory allocator can return values that are far away in memory.
There's an alternate approach that solves all these problems. If you're thinking about the lifetimes of your data, you would notice that this entire data structure is used and discarded at once, so you allocate a single big buffer for all the nodes. You keep a pointer to the head of that buffer, and when you need a new node, you stick it in there and advance the pointer by its size. When you're done you return the first node, which also happens to be the start of the buffer.

Now you have a single point of failure - the buffer allocation, your program is way faster, you only need to free one thing when you're done, and your values are tightly packed in memory, so whatever is using its output will be faster as well. You've spent just a little time thinking about memory and now you have a vastly superior program in every single aspect, and you're happy.

1 comments

Memory arenas are a nice concept but I wouldn't say they're necessarily an improvement in every possible situation. They increase complexity, make reasoning about the code and lifetimes harder and can lead to very nasty memory bugs. Definitely something to use with caution and not just blindly by default.
Reasoning about the lifetimes of objects in an arena is as simple as it gets - there's only one lifetime, and pointers between everything allocated on the arena are perfectly safe. The complexity of figuring out what's going on, with with respect to the number of objects and links between is O(1).

There's no universal "God pattern" that you can throw at every problem. I used arenas as an example as I didn't want to write a zero-substance "OOP bad" post, but my point wasn't that instead of always using OOP+inheritance you should always use an arena, it was that if you think about your memory, more often than not there's a vastly superior layout than a bunch of heap objects glued together by prayers and smart pointers.

That's all nice and fun until you want to pass stuff around and some objects might outlive the arena. Do you keep the whole arena around, do you copy, do you forget to do anything at all and spend a few days debugging weird memory bugs in prod?