According to Solidity documentation, these two keywords are used for Reference Types where

Complex types, i.e. types which do not always fit into 256 bits have to be handled more carefully than the value-types we have already seen. Since copying them can be quite expensive, we have to think about whether we want them to be stored in memory (which is not persisting) or storage(where the state variables are held). … Every complex type, i.e. arrays and structs, has an additional annotation, the “data location”, about whether it is stored in memory or in storage.

It is now important to look at where EVM (Ethereum Virtual Machine) stores data:

The Ethereum Virtual Machine has three areas where it can store items. The first is “storage”, where all the contract state variables reside. Every contract has its own storage and it is persistent between function calls and quite expensive to use. The second is “memory”, this is used to hold temporary values. It is erased between (external) function calls and is cheaper to use. The third one is the stack, which is used to hold small local variables. It is almost free to use, but can only hold a limited amount of values.

Most importantly,

If you e.g. pass such variables in function calls, their data is not copied if it can stay in memory or stay in storage.

This is where it gets confusing:

The storage and memory keywords are used to reference data in storage and memory respectively. Contract storage is pre-allocated during contract construction and cannot be created in function call. After all, it makes little sense to create new variable in storage in a function if it is to be persisted. Memory cannot be allocated during contract construction but rather created in function execution. Contract state variable is always declared in storage. Again, it makes little sense to have state variable that cannot persist. When assigning a memory referenced data to a storage referenced variable, we are copying data from memory to storage. No new storage is created. When assigning a storage reference data to a memory referenced variable, we are copying data from storage to memory. New memory is allocated. When a storage variable is created in function locally by look up, it simply reference data already allocated on Storage. No new storage is created.

To recap, refer back to the documentation:

Forced data location: * parameters (not return) of external functions: calldata * state variables: storage Default data location: * parameters (also return) of functions: memory * all other local variables: storage