1 of 2

It does not produce empty lines.

It moves the cursor to the bottom left-hand corner of the screen, which is where it happens to be sent when you issue a command like :q or ZZ, usually because you have just entered an ex command or because it has updated the status line.

And it only does so because your terminal description in terminfo either does not include capabilities for entering and exiting cursor addressing mode at all, or includes enter/exit cursor addressing mode capabilities that do not employ the DECSM/DECRM Private Mode sequences that command saving/restoring the cursor position in addition to commanding switching to and from the alternate screen buffer. (DEC Private Modes 1047 and 47 only command switching to and from the alternate screen buffer. It is DEC Private Mode 1049 that commands saving/restoring the cursor position as well.)

Normally, immediately upon exiting vim, like other programs that present a full screen textual user interface, exits cursor addressing mode. Because that restores the cursor position from when it entered cursor addressing mode, back when vim and such programs started up their full-screen textual user interfaces in the first place, the cursor is thereby moved from the bottom left-hand corner to wherever it was when the program started.

That lack of terminfo capabilities, in turn, is most probably because you have not used the correct description for your terminal/terminal emulator. The most common error is to abuse xterm, exactly as you are doing it transpires. Unless your terminal emulator really is the XTerm program, that terminal type is wrong for your terminal. Use iTerm.App, vte-256color, tmux-256color, putty-256color, nsterm, and so forth, as appropriate.

Note that the terminal emulators that are built into the Linux, OpenBSD, NetBSD, and FreeBSD kernels themselves, denoted by the linux-16color, pccon, and pcvt25 terminal types, do not have alternative screen buffer mechanisms and so do not have terminfo capabilities for entering/exiting cursor addressing mode, and this is the only behaviour that you will get from any full-screen program on such terminals.

Further reading