Hacker News new | ask | show | jobs
by mrkline 3407 days ago
The main issue with just using newlib's allocator is that we're using FreeRTOS, and (AFAIK), there isn't a good way to make the two aware of each other. One could also probably hook operator new up to to FreeRTOS, but we try to avoid dynamic memory allocation after init, like the article said.
1 comments

> (AFAIK), there isn't a good way to make the two aware of each other

When you set up FreeRTOS you configure which heap implementation it uses. They provide a number of heapX.c files you can choose between. heap3.c uses malloc directly for instance, the others use built-in implementations of a heap algorithm of varying complexity.

If you want to use your own allocator, you just write your own heapX.c file. Use the malloc one as a template and call the newlib allocator instead of malloc. Link that in instead of any other heapX file and voila, FreeRTOS is using newlib to allocate memory.

IIRC, the concern was in the details of newlib's allocator. Its sbrk looks for a linker symbol, then starts slicing memory off of that address. There were worries that unless we were careful, it might stomp on FreeRTOS. (These worries could have been unfounded, but we didn't look into it deeply. We only dynamically allocate at startup, so we'd prefer FreeRTOS's heap_1.c anyways.)
FWIW this is pretty much THE definition of technical debt.
I don't follow. If an allocator is optimized for our needs (i.e., allocating everything up front and never freeing), and is easier to set up than the general-purpose allocator in newlib, how is using it "technical debt"?
"These worries could have been unfounded, but we didn't look into it deeply. We only dynamically allocate at startup, so we'd prefer FreeRTOS's heap_1.c anyways."

The definition of technical debt is not taking the time to understand the components of the system, in favor of getting the system working to a given deadline.

Allocators are "well understood" by the code, which is to say that a lot of programmers assume they know what the allocator can do and what it can't do.

You've chosen to go this route of a static allocator which never frees as your solution because it meets your current requirements, however you've done so under the cover of the API of a more common allocator. This works great and you ship your project and move on.

Now months, or years later, someone else comes along and they are adding a feature or changing a small bit. They need an allocator that can allocate and free from the heap, but since they don't know your allocator can't free they just use the function calls, they all link but the ones to free() don't actually do anything. They run out of memory and die. And they start debugging the problem and realize that you didn't do the work to understand the allocator and to make it work in your setup, so in addition to them having to do that to use it in their code they either have to go back and rewrite your code to use the fully functional allocator, or they leave your code alone (that would be adding still more technical debt since you now have two allocators in the code that operate under different principles).

This is how software systems get so broken over time, people get it working and move on, not taking the time to think about how it is going to be used in the future or even if it can be used in the future. The code that sits there, and will cause future you or future maintainer is "debt" that eventually will have to be paid. Sometimes you can pay it with a refactor, sometimes you have to throw it all out and start over.

You're really making a bunch of uncharitable assumptions about our situation.

First, you assume that this behavior isn't well understood, well documented, and even expected in my organization and our corner of the industry. The reason FreeRTOS has an allocator that doesn't free is because it's standard behavior in embedded systems with hard time requirements.

Then you guess that we've taken no precautions against some future developer not having this knowledge. The allocator in question asserts if the user tries to free to avoid the very scenario you describe, and attempting to use newlib's allocator asserts with an explanation of why it's unused.

Technical debt is an issue I take very seriously, and I work hard to document the design decisions we've made. Choosing to use a tool that's designed specifically for our use case, instead of taking the time to set up a general-purpose allocator with overhead we don't care for, is hardly a debt that needs to be paid off.