I assume that the address-balance mapping array in ERC20 is considered as a storage variable. So say if 1 million users start to use token A, then there would be 1 million entries in the balance array which is expensive to hold in the storage section. How can this be optimized to reduce gas costs?
Ethereum uses Merkle Patricia tree for storage, which provides logarithmic lookup time, therefore the cost of storing a large number of elements does not matter much. In any case, the gas costs of lookup (or other operations) will be paid for by the user who initiated the transaction, not the token contract owner.
Array's in solidity are initialized to the value 0 for all addresses when created. As long as you don't iterate through the whole array, you should be okay. Instead you should store the list of used addresses so that you can easily access all needed addresses at a later point ie: give refunds to everyone who donated to a contract