Understanding RAM consumption

Hi Folks!

I'm coding a micro web server and I see that certain chunks in my code allocate RAM at all and since it's more than the 328 provides, I'm trying to understand why my code in the related sections consumes RAM. In the code attached, you'll see two commented section. If I uncomment those the RAM allocation causes a crash. I'm using the sprintf command since I'd like to introduce some variable parts in those lines later but it already fails right now.
Can you give a hint why these sections consume that additional RAM (besides the already allocated "transferText") and I'd appreciate some guidance how to improve it?

Thanks a lot in advance!

-tuxuser

#include <EtherCard.h>
#include <Arduino.h>
#include <avr/interrupt.h>
#include <avr/io.h>


boolean secondExpired  = 0;
byte Ethernet::buffer[500];
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x35,0x33 };
static byte myip[] = {192,168,1,210};
static byte gwip[] = { 192,168,1,1 };
static byte hisip[] = { 192,168,1,200};
static byte static_dns[] = { 192,168,1,1 };
static byte mymask[] = { 255,255,255,0};


int GetAvailableMemory();
static void response_callback (byte, word, word);

/* ----------------------------------------------------------------------
Setup
---------------------------------------------------------------------- */

 void setup() {

  Serial.begin (115200);

  Serial.println("Test Web Server");
  Serial.println();

  Serial.print ("Available Memory: ");
  Serial.println (GetAvailableMemory ());
 
  if (!ether.begin(sizeof Ethernet::buffer, mymac, 10))
    Serial.println( "Failed to access Ethernet controller");
  else
    Serial.println("Ethernet controller initialized");
  Serial.println();
 
  if (!ether.staticSetup(myip, gwip)) {
    Serial.println("Failed to set IP address");
  }
  ether.copyIp(ether.hisip, hisip);  
  ether.copyIp(ether.mymask, mymask);  
  ether.printIp("IP Address:\t", ether.myip);
  ether.printIp("Netmask:\t", ether.mymask);
  ether.printIp("Gateway:\t", ether.gwip);
  ether.printIp("Server IP:\t", ether.hisip);
}

/* ----------------------------------------------------------------------
Main function
---------------------------------------------------------------------- */

void loop() {
  static bool prevKey0 = 0;
  static bool prevKey1 = 0;
  static char transferText [100] = "\0";
  static unsigned long driveTimer = 0;
  static byte state = 0;



// --- Web Server Part --------------------------------------------------

  word pos = ether.packetLoop(ether.packetReceive());

  if (pos) {
    BufferFiller bfill = ether.tcpOffset();

    if(int cntr = strstr((char *)Ethernet::buffer + pos, "?1=Upper") != 0) {
      sprintf (transferText, "HTTP/1.1 200 OK\r\n Content-Type: text/html\r\n\r\n<html><head>");
      bfill.emit_p(PSTR("$S"), transferText);
  
      sprintf (transferText, "<meta http-equiv=\"refresh\" content=\"0; URL=192.168.1.210\"></head>");
      bfill.emit_p(PSTR("$S"), transferText);

      ether.httpServerReply(bfill.position());    
    }

    else if(int cntr = strstr((char *)Ethernet::buffer + pos, "?1=Middle") != 0) {
      sprintf (transferText, "HTTP/1.1 200 OK\r\n Content-Type: text/html\r\n\r\n<html><head>");
      bfill.emit_p(PSTR("$S"), transferText);
  
      sprintf (transferText, "<meta http-equiv=\"refresh\" content=\"0; URL=192.168.1.210\"></head>");
      bfill.emit_p(PSTR("$S"), transferText);

      ether.httpServerReply(bfill.position());    
    }

    else if(int cntr = strstr((char *)Ethernet::buffer + pos, "?1=Lower") != 0) {
      sprintf (transferText, "HTTP/1.1 200 OK\r\n Content-Type: text/html\r\n\r\n<html><head>");
      bfill.emit_p(PSTR("$S"), transferText);
  
      sprintf (transferText, "<meta http-equiv=\"refresh\" content=\"0; URL=192.168.1.210\"></head>");
      bfill.emit_p(PSTR("$S"), transferText);

      ether.httpServerReply(bfill.position());    
    }


    else if(int cntr = strstr((char *)Ethernet::buffer + pos, "ipAdr=") != 0) {
#ifdef DEBUG_ETHERNET
      Serial.print ("Set IP Address: ");
      Serial.println (cntr);
#endif
    }

    else if (strstr((char *)Ethernet::buffer + pos, "setup") != 0) {
#ifdef DEBUG_ETHERNET
      Serial.println ("Buttons");
#endif
      sprintf (transferText, "HTTP/1.1 200 OK\r\n Content-Type: text/html\r\n\r\n<html><head><title>");
      bfill.emit_p(PSTR("$S"), transferText);
  
      sprintf (transferText, "Server</title></head><body><h3>Server</h3>");
      bfill.emit_p(PSTR("$S"), transferText);
/*
      // Next line consumes ram - lots of ram!
      sprintf (transferText, "<form action=\"input_text.htm\"><p>IP: <input name=\"ipAdr\" type=\"text\" size=\"15\" maxlength=\"15\" value=\"192.168.\"></p></form>");
      bfill.emit_p(PSTR("$S"), transferText);  
*/
      sprintf (transferText, "</body></html>");
      bfill.emit_p(PSTR("$S"), transferText);

      ether.httpServerReply(bfill.position());    
    }
/*    
    // Next lines consume tremendous amount of ram!
    else if (strstr((char *)Ethernet::buffer + pos, "two") != 0) {
      sprintf (transferText, "HTTP/1.1 200 OK\r\n Content-Type: text/html\r\n\r\n<html><head><title>");
      bfill.emit_p(PSTR("$S"), transferText);
  
      sprintf (transferText, "Server</title></head><body><h3>Server</h3>");
      bfill.emit_p(PSTR("$S"), transferText);

      sprintf (transferText, "<form action=\"\"><input type=\"submit\" value='Upper' name=2 style=\"height: 60px; width: 100px;\">
");
      bfill.emit_p(PSTR("$S"), transferText);

      sprintf (transferText, "<input type=\"submit\" value='Middle' name=2 style=\"height: 60px; width: 100px;\">
");
      bfill.emit_p(PSTR("$S"), transferText);

      sprintf (transferText, "<input type=\"submit\" value='Lower' name=2 style=\"height: 60px; width: 100px;\">");
      bfill.emit_p(PSTR("$S"), transferText);

      sprintf (transferText, "</form>");
      bfill.emit_p(PSTR("$S"), transferText);

      sprintf (transferText, "</body></html>");
      bfill.emit_p(PSTR("$S"), transferText);

      ether.httpServerReply(bfill.position());    
    }
*/

    else {
      sprintf (transferText, "HTTP/1.1 200 OK\r\n Content-Type: text/html\r\n\r\n<html><head><title>");
      bfill.emit_p(PSTR("$S"), transferText);
  
      sprintf (transferText, "Server</title></head><body><h3>Server</h3>");
      bfill.emit_p(PSTR("$S"), transferText);

      sprintf (transferText, "<form action=\"\"><input type=\"submit\" value='Upper' name=1 style=\"height: 60px; width: 100px;\">
");
      bfill.emit_p(PSTR("$S"), transferText);

      sprintf (transferText, "<input type=\"submit\" value='Middle' name=1 style=\"height: 60px; width: 100px;\">
");
      bfill.emit_p(PSTR("$S"), transferText);

      sprintf (transferText, "<input type=\"submit\" value='Lower' name=1 style=\"height: 60px; width: 100px;\">");
      bfill.emit_p(PSTR("$S"), transferText);

      sprintf (transferText, "</form>");
      bfill.emit_p(PSTR("$S"), transferText);

      sprintf (transferText, "</body></html>");
      bfill.emit_p(PSTR("$S"), transferText);

      ether.httpServerReply(bfill.position());    
    }
  }
}


/* ----------------------------------------------------------------------
Ethernet Response Handling
---------------------------------------------------------------------- */

static void response_callback (byte status, word off, word len) {
} 


/* ----------------------------------------------------------------------
Determine Available Memory
---------------------------------------------------------------------- */

int GetAvailableMemory() {
  extern int __bss_end;
  extern void *__brkval;

  int free_memory;

  if((int)__brkval == 0)
    free_memory = ((int)&free_memory) - ((int)&__bss_end);
  else
    free_memory = ((int)&free_memory) - ((int)__brkval);

  return free_memory;
}

This causes the SRAM depletion. It transfers the static strings into SRAM before using them.

  Serial.println("Test Web Server");

This does not transfer them to SRAM. Note the F() macro.

  Serial.println(F("Test Web Server"));

String constants take up space in SRAM. You can keep strings in PROGMEM (FLASH) but then you need special functions to deal with the PROGMEM pointers because they use a different address space. For example to use a format string in PROGMEM you need to use sprintf_P():

sprintf_P(transferText, PSTR("HTTP/1.1 200 OK\r\n Content-Type: text/html\r\n\r\n"));