Keep in mind that RAM is even less. 32KB is a fair lot of code, since C/C++ is highly efficient. "Don't save shit**** in RAM."
If you need to load images into a display, save the images on an SD card. And "stream" it to the display. You can read and transmit the bytes one by one, or 10 by 10 or something.
Also, if you need long strings, you can use the "flashStringHelper" to store the string in flash memory. For example: println(F(”Error message: Couldn't connect to server));. By using F() around the string, you save valuable bytes.
Not using Arduino code, but pure AVR-C/C++, can save you a little also. (Will also save the bootloader piece of memory, if you program directly with a programmer.)
If you use Arduino, know how it works. The Arduino serial library uses ~256 or 500 bytes (I believe) as a buffer. You can change this if you need it for other applications.
Keep in mind that your saving technique depends on what resources are low. If you need to do a lot simultaneously, it's better to write non-blocking code.
But also remember: Don't optimize unless it's actually needed! Or, actually set measurable and realistic requirements, optimizing something to be "as fast as possible" can take infinite amounts of time... Run a google search on "premature optimization" as the old folks in the field like to call it.