This is just an off-the-head list.
- Spatial locality
- Temporal locality.
- Easily-predictable memory access patterns.
- For example, reading/writing megabytes of data sequentially is not at all inefficient, because the CPU can predict the next address and automatically read ahead.
Programming language constructs.
- Data alignment directives.
- Switching between array of structure and structure of array.
- Vectorized data containers provided by high-performance libraries.
The compiler has already done some of the work for you. For example, groups of functions that are closely related (for example, likely to be called in successive sequence) will be compiled into binary instructions and then stored close to each other, so that they reside within the same 4KB page block. There is simply no way for a developer to cater to such details manually.
For native compiled languages, local variables are stored on the stack, and the area closest to the current stack position is likely to be cached. If a large variable (several KBs or more) is allocated from the stack, the CPU may have to evict something else from the cache to make room. On the other hand, if the large variable is used very frequently, then allocating from stack can be justified.