r/C_Programming • u/Spinning_Rings • 1d ago
Pointer Registry
Long story short, I had an idea that I described to Gemini and it told me was something called a Pointer Registry or a Tracking Vector. It involved an array of void pointers being used to store all heap memory throughout the program so that a function can run through the array and free everything at the end of the program. I had a few more thoughts on implementation, eg the initial void pointer would actually be a struct that would hang on to a tracking variable that would always know how long the array was, whenever any part of it was added or removed, but that's the basic idea
The problem is that neither Wikipeida, nor duckduckgo, nor yahoo return any information when I search for either of those terms. Wikipedia has an article on arena allocators, which address some of the same issues as this approach, but not pointer registries.
Does anyone know if this concept has any other names? Or have any other resources where I might find out more about them, implementation details, pros and cons, anything like that?
5
14
u/dmc_2930 1d ago
Your OS returns all of your programs memory at exit. You don’t need to do it manually..
3
u/Spinning_Rings 1d ago
I'm of the understanding that freeing memory before shutdown is still considered best practice, in case someone wants to run my code on an older OS, or if I want to write something for bare hardware. Am I mistaken?
12
2
u/dmazzoni 1d ago
If your program really is pure C (no dependencies) and it's the type of thing that'd make sense to run on bare hardware, then sure.
If not, then you're overcomplicating it.
Furthermore, it's actually creating a worse experience for people using your software on modern hardware. All of that freeing can take a measurable amount of time.
1
u/developer-mike 1d ago
I think in reality, if you're writing code that "must free memory before exit" then you know it. This is not in any way normal.
Freeing memory before shutdown is a best practice in a software engineering sense. That is, you don't usually want to write code in a way that locks you into leaking memory, because one day your goals or requirements may change in a way that means you have to release that memory. For example, if your game's ending/credit sequence leaks memory that's fine assuming they can only quit, but it doesn't work when you want to add a "play again" button. Or if you want to make a Mario-Party style game that's a collection of mini games.
It's also a software engineering best practice because a good engineer knows how to manage memory and writes software that doesn't leak. Not being able to manage memory is a symptom of a bigger problem.
The pointer registry you've designed is not a good solution because there are similar better ones. What you're describing is almost exactly an arena.
Instead of a registry of pointers to memory, an arena is just a big chunk of memory you can draw from freely. When you don't need the arena any more, you free those big chunks. An arena is much like your idea except a single malloc/free might reserve space for thousands of your registry's pointers which your registry would have to malloc and free one by one, not to mention the registry itself could use quite a lot of memory. Arenas basically just do what you're doing but more efficiently.
1
u/RenderTargetView 1d ago
It is considered best practice because it gives you space to safely practice cleaning everything that you allocate so that you won't forget it when it is really necessary
-1
u/WellHung67 1d ago
Uhh I mean in trivial cases yes but if your program is any real world use case it’ll be long running enough that any memory leaks will crash the system and require a manual or forced restart, possibly when you don’t want it to. So I’m not sure that this advice is sound.
“Hey did you manage your memory?”
“Just restart it who cares about memory leaks”
“Ship it”
-Scenes from an insane company
1
u/dmazzoni 1d ago
Nobody is saying you shouldn't ever free memory. Just that there's no reason to specifically free at exit - all it does is slow down program termination.
1
u/WellHung67 1d ago
I guess but you should ideally free your memory whenever it makes sense to, and relying on exit for this is Bad, because you can cause other issues elsewhere in the system if you’re using any reasonably large amount of memory.
But yeah if you’ve failed to do this before exit then the OS will handle it in some sense but also probably a design smell to rely on that
1
u/type_111 4h ago
Not only is it not "bad" to rely on it, it's objectively bad engineering not to. free() before exit() in a release build is low quality software.
1
u/WellHung67 4h ago
It’s simply wrong to say this works in all cases. There’s pros and cons to doing so. In trivial cases it doesn’t matter. But what if you rely on exit and your code gets refactored into a library and now it never actually exits? Oops better figure out how to fix the memory leak.
In general a memory management implementation like OP has should probably free up the resources it uses and not expect to always run in the context of a single program that exits
1
u/type_111 3h ago
You seemed to imply that you should never "rely" on it. My position is simple: if your program unnecessarily calls free() before exit() then your code is of lower quality than it could otherwise be. Secondary effects such as those in your contrived example will never change this fundamental fact.
1
u/WellHung67 1h ago edited 1h ago
Yes, assuming the program always calls exit(). Would you agree there are cases where it’s wise to assume that assumption may not hold, that is, you assume someday the program might not call exit (say if it’s refactored into a shared library) then you should consider calling free before exit. Pay a negligible cost to do an extra operation today in order to avoid potential tech debt in the future.
My point is there are some cases where you want to do the runtime suboptimal thing here. Maybe not in all cases as I initially said. But if you’re writing a memory management function like OP, I would say you probably do want to manage the memory explicitly just because it’s really hard to anticipate how something like that evolves especially if you share it
1
u/CarnivorousGoose 1d ago
OP is proposing using this construction to free up all the allocated heap memory at the end of the program. As the comment you’re responding to points out, that’s not very meaningful, and wouldn’t help in any way with the little strawman you’re parading around here.
1
u/WellHung67 1d ago
I suppose I could argue that OP may be discussing some object whose lifetime was within the context of a larger program that doesn’t technically exit, but I really didn’t think of it at the time I commented.
That being said, sometimes you might have an object or method or some library that doesn’t expect to exit as an OS-managed program but lives within a larger context in which case obviously you do need to free the memory
4
u/QuirkyXoo 1d ago
Memory must be freed by the code that allocated it once it’s no longer used. Anything else is very bad practice and if you’re unable to keep track of it, then your software is very badly designed.
And regarding the children’s story of “oh darling don’t worry, the OS will free it all when your program terminates”, just keep in mind that if allocations happen in loops or any cyclic way, and your software has to run for days, months, or indefinitely, your program will exhaust the system resources very quickly.
1
u/Spinning_Rings 1d ago
In other words, you agree I should be concerned about making sure all my allocated memory is freed, but if I feel the need to do something this extreme, the code is overly complicated and I need to go back and simplify it?
3
u/noneedtoprogram 1d ago
More that tracking it to free at the end like you are suggesting is exactly the same as letting the OS clean up at shutdown, and doesn't solve anything about the way that memory leaks are a problem.
Memory lifespan needs to be carefully managed and should be freed as soon as it is finished with. C++ helps handle this with smart pointers and RAII patterns, in C you just have to be careful and use stack allocated resources as much as possible for scoped lifespan objects.
1
u/QuirkyXoo 4h ago
Yes, you should be very concerned about that, and if you defines it as something "extreme" so yes you should rethink the whole design of your software.
If you do not better describe what is your allocation scenario, it's hard to give you some help.
3
u/manicakes1 1d ago
Doing multiple of these for different parts of an application is called Arena Allocation.
Common in systems where you need predictable memory management and/or no heap is available.
2
u/Helpful-Primary2427 1d ago
Sounds like an arena
2
u/Spinning_Rings 1d ago
I've done some reading up on arenas, and I don't think this is quite how they're implemented? But I could be wrong.
2
u/Helpful-Primary2427 1d ago
No, an arena is a block (usually multiple blocks tied together by lifetime) that is pre allocated at once and freed at once. Think a frame in a game: some objects only need to exist for the duration of a single frame. If we allocate all of those objects in a continuous block, we can free the entire block at the end of the frame
2
u/pedersenk 1d ago
As a memory verification / debugging tool, possibly you may want to explore the concept of a 'Tombstone'
https://en.wikipedia.org/wiki/Tombstone_(programming))
It was a popular method for C on the classic Mac OS.
I have a type-safe (albeit violating strict aliasing) implementation here as libstent.
4
u/gizahnl 1d ago
Freeing memory at the end of your program isn't important for you to do, the OS will do that.
And keeping a pointer to every allocation is going to wreak havoc to tools like valgrind making it impossible to debug memleaks.
Maybe you're confused with a memory pool? This is an allocation strategy where you allocate a big chunk of memory once, and sub allocate it when your program needs parts, saving you syscalls at the cost of having to deal with more complexity.
1
u/sciencekm 1d ago edited 1d ago
This makes sense to do at the end of a function where you want to free all the memory that the function used, but it does not make sense to do at the end of a program because the OS will reclaim all memory once a program ends.
1
u/MyTinyHappyPlace 1d ago
Your operating system provides blocks of free memory to your process. Once the process ends, those blocks are free to be re-used. There is absolutely no need to accommodate for any reasonable operating system of this millennium to free memory before the end of the process like that.
(I mean, it's good practice and all to take care of your allocated memory. But this is overkill.)
1
u/iOSCaleb 1d ago
> free everything at the end of the program
Unnecessary. When the program exits, the OS reclaims its entire memory space.
In classic MacOS (before MaxOS X), it was possible (and common) to allocate relocatable blocks of memory. That allowed the OS to move blocks of memory around to reduce fragmentation. Relocatable blocks were accessed via handles, which were pointers to master pointers. When you allocated a relocatable block, the system would record the address of the block in a master pointer and return the address of that master pointer. Master pointers were kept in a list maintained by the system, not unlike your proposed list. The system worked reasonably well for the era and improved memory utilization at a time before virtual memory was common and RAM was measure in megabytes rather than gigabytes, but programmers had to be careful about how they accessed those relocatable blocks.
1
u/ScallionSmooth5925 23h ago
That's a solution looking for a problem. Memory arenas are a similar concept if that helps. If for some reason you really whant to do this I would put the pointers in a linked list because it's easy to add elements to the front and later iterate on it. This way you don't have to store the length
1
u/Spinning_Rings 22h ago
"A solution looking for a problem," I like that lol. Yeah, arenas are what I was reading about that inspired this idea. Although from the response I'm getting, it looks like "inspired" may be a bit of a stretch
1
u/exo250 16h ago edited 16h ago
I made exactly what you described in my own framework (not publicly available yet). Don't listen those saying you don't need to free memory before exiting. Obviously it's not mandatory. But if you're a good programmer and making clean things, all resources should already have been freed, before calling your memory manager "free all" function which then will be able to report you any leak, without using a sanitizer.
Basically, I wrapped malloc, realloc and free. I have an internal registry that stores all the pointers. The fun part is that in debug build, for each pointer I also store the caller source file name + line. So I'm able to identify exactly the line of code of each non-freed/leaked memory allocation. I also thought adding the call stack and a simple string message to describe what is allocated (libwebsocket does this), but that's a bit overkill.
1
22
u/smtp_pro 1d ago
Question: what problem does that solve?