For most applications the hardware requirements are irrelevant. Very few programs stress a computer sufficiently to require the developer to give a damn. 8192kb or 10,000kb makes no odds. You use as much storage as suits your purposes and it either fits or it doesn't. If it doesn't fit (which is pretty damn' rare) it will be by such a magnitude of difference that a couple of mega bytes is neither here nor there.
Where I worked we spent a good deal of our time carving up application code and data areas into banks of memory that would fit into the addressing limits and still have the rights areas visible at the time each machine code in each of 50 odd threads was executed. Every last word of memory counted and debugging non-visibility problems was all part of the game where the trusty octalator was very much an essential tool as you pored over stacks of binary dumps with highlighter pen and strips of post-its to mark them up.
Oh aye, in the past. I remember doing that myself back in the late 90s. People developing software for embedded controllers likely still do.
But for most developers on most systems these days it's just a none-issue. Even if it were an issue most things simply don't fit into that scheme. It would be hugely wasteful to round everything up so that a power of two size was used. All it takes is for one item not to follow that rule and everything higher up memory is on a 'nuisance' boundary.
In fact with managed languages like Java and the .NET family the concept of a 'memory address' barely exists. Back when I was new to C# I tripped over that several times. Just because you have:
SomeClass sc=new SomeClass();
does not mean that 'sc' is a fixed numerical value. It can and likely will change without you knowing about it (objects get moved around over time as the garbage collector does its stuff). Anyone that has passed a 'pointer' from managed to unmanaged code will find that out the hardway. Even function pointers will change which is where I first fell into the trap. I passed the address of a static function into unmanaged code and when it tried to call it back it sometimes crashed. Turns out the static function wasn't always where I'd left it
In C++:
int f=(int)sc;
Is valid and only moderately stupid (mainly because of the loss of typing information). If you reverse that later and know what you're doing it's quite safe.
In C# it won't compile and is meaningless and very dangerous. Reversing it would result in undefined behaviour no matter when you did it.
Tempres fugit, I guess :-/