Global variables that are not given explicit initializers, like yours in this case, are initialized to 0's by default. They are placed into an area of memory called the .bss segment, and no additional data is stored in the object file/executable file indicating the initial value of the data (unlike explicitly initialized data, which has to have its initial value stored somewhere).
When the OS loads the program, it reads in the descriptions of all of the segments and allocates memory for that. Since it knows that the .bss segment is initialized to all 0's, it can do a sneaky trick to avoid having to actually allocate tons of memory and then initialize it to all 0's: it allocates address space for the segment in the process's page table, but all of the pages point to the same page, filled with 0's.
That single zero-page is also set to read-only. Then, if and when the process writes to some data in the .bss segment, a page fault occurs. The OS intercepts the page fault, figures out what's going on, and then actually allocates unique memory for that page of data. It then restarts the instruction, and the code continues on its merry way as if the memory had been allocated all along.
So, the end result is that if you have a zero-initialized global variable or array, each page-sized chunk of data (typically 4 KB) that never gets written to will never actually have memory allocated for it.
Note: I'm being a little fuzzy here with the word "allocated". If you dig into this sort of thing, you're likely to encounter words such as "reserved" and "committed". See this question and this page for more info on those terms in the context of Windows.