This is a somewhat tricky question dealing with implementation and best-practices of the ESP8266. I'd ideally hope that it's answered by people with in-depth knowledge on the problem.
As you are hopefully aware, the Arduino (AVR) platform requires the use of the PROGMEM or F() instructions to avoid copying all strings to RAM. The ESP8266 platform also provides a PROGMEM instruction, but is memory-mapped.
I thus have several questions about what the PROGMEM instruction actually does on the ESP8266.
For the next few questions, until otherwise marked, I am referring to character-array-style C strings, not the Arduino String type.
Storage of constant strings: If I were to declare a string (global, for now) on the ESP8266, would it be read from flash only when it's accessed, or will it always take up RAM (like it would on the AVR. Assume that in this case I do NOT declare it as PROGMEM; I wish to find out what the default behavior is on the ESP8266)?
Local Constant Strings: What happens with strings that are used inside a function? I am fairly sure that they ALSO exist in RAM, at least in AVR. Does the ESP8266 do this too, or does it (potentially) store it in flash until it is read (it is fine if it ends up inside a cache somewhere, as long as it can be evicted if needed)?
Use of String(F("mystring")): If I wrap a PROGMEM string in this manner, does this truly convert the string into a RAM-based string only when this line is reached, or does this for some reason initialize the String() early (and consume the RAM anyway)? Do the systems differ in this behavior?
If I define several instances of the above (as in, the identical wrapped string shown above appears several times, perhaps in different functions), do all of them point to the SAME F() instance (since they are identical) or does it get duplicated since it's part of code rather than a referenced variable? On ESP8266? On AVR?
On the ESP8266, I discovered that the server.on() function for the built-in webserver read F()'d constant strings just fine, but failed to work once the file grew beyond the size of the RAM. It was clearly stored correctly, but it could not be read. I thus conjecture that the method was making a local copy to RAM, even if the file was stored in Flash. There was also a on_P version that worked after that point (I believe I used PSTR rather than F at this point as well, since -- correct me if I am wrong -- the two are not compatible). Is this the real point of PROGMEM on ESP8266? That the data is only stored in Flash, but it also tells the function reading it to make as few copies as possible or chunk it?
I am also curious what happens with large strings that aren't constant. The web server can return data that was passed via querystring, for instance, which in my case can be quite large. If I copy that data to a string (and then into a function), does it pass the heap pointer directly, or does each String make a new copy? I am concerned about fragmentation or other fun ways of running out of RAM even if one copy should in theory fit.
Does doing something like bool myFunction(String &str){...}
help? Some sort of way to actually ensure that it's the same string, rather than copying (and can I do String &myStr=server.arg(...)
-- is a return value different from an assignment)? It's confusing for me, since strings are clearly passed by value, despite being a complex datatype with dynamic memory somewhere in there. So, did they override the assignment operator (and/or the one that handles reference passing, since I think there's more than one) to duplicate the string as pass-by-value of a basic type would normally do, or do they share pointers (and thus memory) as a class passed-by-value would normally do?