Home > database >  Memory isn't freed when scope is left in C
Memory isn't freed when scope is left in C

Time:06-27

I'm fairly new to C so please forgive me for my ignorance. I'm under the impression that anything between { and } is called a scope, and that you can create a separate scope inside a function, or anything else, just by adding more brackets. For example:

int foo(){
    std::cout << "I'm inside the scope of foo" << std::endl;
    {
        std::cout << "I'm inside a scope that's inside the scope of foo" << std::endl;
    }
}

I was learning about this in relation to pointers and memory leaks. My understanding is when you leave a scope all variables should be freed from memory unless the memory was manually allocated with new or malloc. In my testing, however, this does not seem to be the case. I've written the following script to test this:

#include <iostream>

void test(){

    {
        int regdata = 240;
        int* pointerInt = new int(1);
        *pointerInt = 15;
        std::cout << "RegData Addr: " << &regdata << std::endl;
        std::cout << "Value:        " << regdata << std::endl;
        std::cout << "Pointer Addr: " << &pointerInt << std::endl;
        std::cout << "Pointer:      " << pointerInt << std::endl;
        std::cout << "Value:        " << *pointerInt << std::endl;
        std::cout << std::endl;
        std::cout << "Press any key then enter to leave the scope.";
        char temp;
        std::cin >> temp;
        //delete pointerInt;
    }

    std::cout << "The scope has been left." << std::endl;
    std::cout << "Press any key then enter to leave the function.";
    char temp;
    std::cin >> temp;
}

int main(){
    test();
    std::cout << "The function has been left." << std::endl;
    std::cout << "Press any key then enter to leave the program.";
    char temp;
    std::cin >> temp;
}

I start this program on my Windows 10 computer and have been monitoring the memory usage using the program Cheat Engine. Now, depending on whether or not I have delete commented out it will delete the bytes that hold 15 and replace them with random bytes when I leave the scope as it should. However, the memory holding the 240 is not freed until after I leave the scope of test (at which point the 240 is replaced with 1). And regardless of if the delete is commented out, the actual pointer itself is never deleted out of memory.

Is my compiler or my machine not compiling/running my code correctly? Or am I misunderstanding memory management between scopes? If it's the latter, please correct me so I can properly understand what is supposed to happen. Also let me know if something doesn't make sense!

CodePudding user response:

Memory is not "freed" when you leave a scope. The lifetime of all variables with automatic storage duration that were declared within that scope end. What happens when the lifetime of a variable ends? For simple values like an int or a pointer: likely absolutely nothing. The lifetime of the variable has ended, so attempting to use it results in undefined behavior, but usually nothing will immediately happen to the value. The compiler knows that the storage in which the variable resided is now available to be re-used, but until it actually re-uses it the old value will likely continue to exist. A compiler could immediately zero out the memory of variables whose lifetime has ended, and for a debug build maybe it will, but doing so would take time so most compilers won't bother.

CodePudding user response:

regdata is stored on the stack so the memory it uses will never normally be "freed" until the end of the thread that the code is running in.

What does happen is that the stack memory is now available again to be used for something else. Your calls to std::cout and std::cin will both need to use a certain amount of stack memory, if they use enough memory then they'll overwrite all of the values in your inner scope (depending on the implementation of your compiler, there's no guarantee that it'll reuse the inner scopes stack memory later in the function, it might decide it's faster to use more stack memory instead).

This is why regdata is always being overwritten with 1, it's a coincidence of later stack usage rather than a deliberate action by the compiler. Some compilers might deliberately overwrite stack memory after its released to help with debugging but in a normal release build that would be an unnecessary waste of time.

  • Related