Jump to content

How much memory do functions take?

Gat Pelsinger
3 hours ago, Gat Pelsinger said:

I agree with your opinion. But in my view, not needed memory is waste of memory, and memory is expensive. It is okay if using more memory makes your code run faster, but the memory that you will just not need afterwards is waste.

You need to keep in mind that you're talking about memory savings measured in megabytes or maybe even kilobytes. Most modern computers have tens of gigabytes of memory. Optimizations at the level you're thinking about is something worthwhile for embedded platforms, but not on PC.

 

The majority of a program's memory usage is the data it has to work with, not its code. Memory for data can be dynamically allocated on the heap and freed when it is no longer needed. Variables only exist on the stack short term, they are gone when the function that uses them goes out of scope. The only thing that remains in memory is the code itself.

 

Unless you're constantly running out of memory, it really is a non-issue. If you do run out of memory, there are likely more memory intensive things you can optimize before it ever makes sense to think about removing code from memory.

 

Memory reserved by programs that are currently idle is also something the OS can automatically move to swap to make more RAM available. Which is a far simpler solution that dynamically loading and unloading functions.

 

Also, what does "afterwards" even mean in this context? Most programs aren't going to contain a ton of code that only runs once and then sits idle until the program is restarted.

 

3 hours ago, Gat Pelsinger said:

The overhead you mentioned might be true but it doesn't seem as dramatic as you expressed, and upon that, the programmer is the one who will look after this optimization and the system doesn't need to care about it, so if a function is deallocated and it is called in the program later, the program is free to crash.

You can certainly move that burden onto the developer/compiler. As @QuantumRand pointed out, some console architectures do this. But for any decently complex program that is still a fair amount of additional complexity developers have to deal with.

 

You'll effectively need to write meta-code that loads and unloads other code before you can do the things you actually want to do. Add multi-threading on top of that and you're dealing with an absolute nightmare.

 

3 hours ago, Gat Pelsinger said:

what are the ways I can get rid of such memory that I do not need?

Your average program is likely never optimized to such a degree that the few kilobytes of memory used by its code are an optimization worth thinking about. Worry about the megabytes or gigabytes of memory used by its data first.

 

When you're optimizing code, start with the slowest and/or most memory hungry parts of it. Anything else is a waste of time; the possible performance improvement isn't worth the effort.

 

3 hours ago, Gat Pelsinger said:

Does that mean I can create multiple code blocks (which I didn't even know you could do in C. I thought code blocks are only used for C keywords like for, if, while, etc), and the memory will be freed after the block exits?

Yes, you can create blocks of code. The most common block of code is called: a function 😜

 

When you enter a function, its variables are allocated on the stack. When you exit the function, its variables are removed from the stack. Loops are also blocks of code. And you can create blocks without having to write a function header (effectively anonymous functions).

 

The only thing that will remain in memory is the actual code, so that it can be called immediately whenever it is needed. Which, again, is memory usage that is likely not worth optimizing unless you're on a super memory constrained embedded architecture.

 

If you want to reduce the memory footprint of your code, write more efficient code first (i.e. try to achieve the same in fewer lines of code).

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

6 hours ago, Gat Pelsinger said:

The overhead you mentioned might be true but it doesn't seem as dramatic as you expressed, and upon that, the programmer is the one who will look after this optimization and the system doesn't need to care about it, so if a function is deallocated and it is called in the program later, the program is free to crash.

Most modern operating systems and modern compilers know how to work together to do a "good enough" job of optimizing the handling of program memory. Most modern operating systems will have a page/swap file, and a modern compiler knows how to inform the OS when sections of program memory are stale and can be moved into the page file (and out of memory). On an unconstrained system like a consumer PC, it's a waste of time to try to optimize your program memory footprint. That time is much better spend optimizing CPU cycles and data storage.

 

Quote

And one more question I have, if a stack allocated variable goes out of scope, does it get deallocated?

This is called Garbage Collection. It's something that C does not do automatically, so you as the programmer need to be aware of when allocated memory is no longer needed and call realloc() or free() for that variable.

Link to comment
Share on other sites

Link to post
Share on other sites

41 minutes ago, QuantumRand said:

 

 

This is called Garbage Collection. It's something that C does not do automatically, so you as the programmer need to be aware of when allocated memory is no longer needed and call realloc() or free() for that variable.

I am talking about stack allocated.

Microsoft owns my soul.

 

Also, Dell is evil, but HP kinda nice.

Link to comment
Share on other sites

Link to post
Share on other sites

My apologies for not being as active this week, I've been very busy with university work lately.

 

On 1/28/2024 at 10:09 PM, Gat Pelsinger said:

@dcgreen2k I just wanted to come back to this thread and ask, that your example includes a very large program, which might have really large vectors, and code that only runs in a loop and acts on the data, in which case, the instructions to data memory ratio would be huge.

Quite the opposite, actually. My comment that it was a large program referred to the amount of source code, of which there are over 5000 lines. The code for this simulator isn't just "Read a line of assembly code, then do something based on what it says", it's more like:

  1. Read the assembly source file and tokenize it (Move away from a string representation as soon as possible)
  2. Parse the token representation to see if it's syntactically correct
  3. Turn the tokens into an easily interpretable list of instructions
  4. Associate source code labels with instructions and variables
  5. Populate the simulator with the instructions and variables in data memory
  6. Take user input to either single-step through the code or run continuously

In short, there's a boatload of setup to do turning source code into something easily interpretable. This is so that we can check if the program is valid and minimize the amount of additional processing the CPU simulator has to do. This also means there aren't too many data structures that live until that last step. I suspect that a significant portion of the 113MB of RAM being used in my previous screenshot is due to the GUI library I'm using, Qt. Thankfully, I also made a command line only version of the program, so we can check that pretty easily.

 

image.png.aab80e35f805e0d4f43bc153d6426fb0.png

 

The command line version uses just 3328 bytes of RAM for its data, which I find quite surprising. To check this, I went through the code and looked for all the data structures that live to that last step.

  • The UI controller takes up 768 bytes on the stack
    • Lots of small variables to control the program and processing thread
    • 1 std::queue to pass messages to the processing thread
    • Some input/output stream pointers to direct text output wherever the user wants
  • The CPU simulator takes a minimum of 1620 bytes, of which 596 are on the stack
    • 2 std::arrays, 1 for the register file and another for a jump table
    • 2 std::vectors, 1 for instruction memory and the other for 1024 bytes of data memory
    • 2 std::unordered_maps for associating labels with instructions and the addresses of variables in data memory
    • A couple small variables for bookkeeping

As you can see, the program is surprisingly lightweight and shows that the high RAM usage was indeed due to the GUI library I was using. Only 5 of the data structures are allocated on the heap, those being the queue, vectors, and unordered_maps. Out of these, only the queue may grow in size after the setup is finished.

 

The size of the compiled code is around 160kB, so now there's much less data compared to the instructions.

 

------------------

7 hours ago, Gat Pelsinger said:

I am talking about stack allocated.

Yes, stack allocated variables are "freed" automatically when they go out of scope. This is why they're sometimes also called automatic variables. I put freed in quotes here because there's no call to free() like there is for heap allocated memory, but rather the space they take up is left as is and overwritten by later code.

 

The way this works is that, when you enter a function, there will be an instruction that grows the program stack by some amount dependent on how much space is needed by that function for its variables. The function is then able to use this new area of the stack (called a stack frame) however it likes. When that function exits, it shrinks the stack by the same amount as before, leaving it in the same state as it was before the function was called.

Computer engineering grad student, cybersecurity researcher, and hobbyist embedded systems developer

 

Daily Driver:

CPU: Ryzen 7 4800H | GPU: RTX 2060 | RAM: 16GB DDR4 3200MHz C16

 

Gaming PC:

CPU: Ryzen 5 5600X | GPU: EVGA RTX 2080Ti | RAM: 32GB DDR4 3200MHz C16

Link to comment
Share on other sites

Link to post
Share on other sites

@dcgreen2k 

 

You don't need to apologize but glad you replied. I don't know what is happening in your code and it seems pretty complex. If you know how to measure the memory usage in such detail, can you measure the memory usage for a very simple Hello World program, and then maybe any other just a little complex program that has a lot of logic?

Microsoft owns my soul.

 

Also, Dell is evil, but HP kinda nice.

Link to comment
Share on other sites

Link to post
Share on other sites

There are many tools out there for memory detection. You can use valgrind, you can use the profiler in visual studio if you use it to see its memory usage, you can open the task manager on windows or use some cli tools like htop on *nix os to see their process memeory usage. 

Sudo make me a sandwich 

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×