Sometimes I write for a particularly non-technical audience, because I know a lot of smart people who don't have my background, but like to get peeks into my world. This is gonna be that kind of article: nothing novel for most programmers, but a tour of ideas and terminology for everyone else.

To talk about memory management, I'm going to first give a recap of what memory even _is_ on a computer. Memory is basically made of a long series of tiny slots, each of which has a tiny number in it. Each slot has an ID number, and you can say "get me the tiny number in slot #500" or "set the tiny number in slot #123 to be 85". These tiny numbers are called **bytes.** Each of them is made of 8 **bits** (a bit is a one-or-zero digit), and if you work the math out, that means each byte can hold a number from 0-255. Like I said, bytes are tiny! But you can treat a few bytes in a row as just a bigger binary number with more digits, so when you see a big number, that's a few bytes being treated like a single big number. The slot IDs are called **addresses**, and when we say a computer is 32-bit or 64-bit or something, that's (mainly) referring to how many binary digits are in an address on that computer. Addresses are binary numbers too, after all.

## Allocation

Here's the thing about addresses. Just because you can say "slot #500" doesn't mean you necessarily have _permission_ to save or load a byte from that address. Even if you're running on bare hardware with no operating system, your **address space** (the range of addresses you can say in 64 bits or what have you) is probably a _lot_ bigger than the actual amount of RAM on your machine. So if you ask for slot #500 when your computer only has 300 slots, you're going to get some kind of error.

In real life, you'll probably be running as a program inside an operating system. The operating system makes sure that programs can't mess with each other's memory, so there will be slots you can't touch because they belong to someone else. That's not yours! Get your own!

Huh. Well actually, how _do_ you get your own?

Well, when your program starts, the operating system gives you some memory up front. You can ask for more if you need it. Since there's a finite amount of memory on the whole computer, your operating system has to keep track of which parts of memory it's given to which programs, so it doesn't give the same region to two different programs by accident, and knows when it's run out of memory. It's kinda like a household budget.

This idea of dedicating part of the total amount of memory to a specific purpose is called **allocation.** Of course, if you only ever allocate, you eventually run out of free memory, so when you're done using a piece of memory, you should **deallocate** it, so it can be reused for something else, reincarnation style. This is also called **freeing** the memory.

Obviously, your operating system is doing allocation and freeing at a big scale, like how it allocates some memory when starting a program, and frees that program's memory when it ends. That's the big picture. But on a smaller scale, it's slow to be constantly asking the operating system for permission to use memory a tiny little piece at a time. So your program is going to do its own _internal_ budget tracking. It's going to keep track of the memory it's gotten from the operating system, carve that into smaller pieces for smaller/more specific purposes, and ask the OS for more memory (in big chunks at a time) when it runs out. And that's _also_ allocation! In fact, usually when we talk about memory allocation, we're talking at this smaller program scale.

The good news is, as a programmer, you usually don't need to reinvent all the "ask the OS for logic in big chunks, divvy it up internally as needed" logic (the **memory allocator**). Even in a low-level language like C, you're going to have some sort of memory allocator available that somebody else wrote, and you don't have to reinvent the wheel about it. In fact, here's how it works in C with the C standard library:

```c
#include <stdlib.h>

int main(int argc, char **argv) {
  // A "char" is just a byte.
  // When you see "char", think "byte".
  
  // malloc means "memory allocator".
  // We tell it how much memory we want (20 bytes),
  // and we get back an address (slot ID) for the space
  // it found for us to use. We store the address in "buf".
  char *buf = malloc(sizeof(char) * 20);
  
  // Okay, imagine we did something with "buf".
  // But now we're done with it, so we should free it.
  // Guess what the function for that is called?
  free(buf);
  
  return 0;
}
```

Awesome! That was... surprisingly painless? Ask and ye shall receive!