-
Notifications
You must be signed in to change notification settings - Fork 13.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
malloc() fails when allocating ESP.getMaxFreeBlockSize() bytes #7322
Comments
You're doing a Serial.printf() in between the maxBlock and malloc operations, which could alloc. Then you have another printf in between malloc attempts, and yet throughout you keep assuming that the maxBlock hasn't changed. |
Thank you for clarifying my mistaken assumptions! My bad... #include <ESP8266WiFi.h>
void setup() {
Serial.begin(74880);
WiFi.mode(WIFI_OFF);
uint16_t maxBlock = ESP.getMaxFreeBlockSize();
uint32_t freeHeap = ESP.getFreeHeap();
Serial.print("free: ");
Serial.print(freeHeap);
Serial.print(" - max: ");
Serial.println(maxBlock);
// re-get maxBlock so no print is between
// this and the first try to malloc()
maxBlock = ESP.getMaxFreeBlockSize();
void* p = NULL;
while (p == NULL)
{
p = malloc(maxBlock);
Serial.print("malloc(");
Serial.print(maxBlock);
Serial.print(") = ");
Serial.println(p ? "success" : "fail");
--maxBlock;
}
}
void loop() {}```
And the debug output is ets Jan 8 2013,rst cause:2, boot mode:(3,6) load 0x4010f000, len 1392, room 16
|
Still not valid. Only the very first failed malloc is correct to fail (see explanation below). Then you print right after, at which point the maxBlock could change (would likely be smaller). You need to keep track of the state in variables, then print out the results only after you've reached a conclusion and your while loop has ended. About malloc fail: the returned value of maxBlock is the "biggest chunk of contiguous free memory". It does not mean that you can allocate the entire block for yourself, because each allocation has an overhead to keep track. |
OK, I'll do it all in variables: #include <ESP8266WiFi.h>
uint8_t counter = 0;
#define MAXTRY 32
uint16_t maxBlockBefore[MAXTRY];
uint16_t maxBlockAfter[MAXTRY];
void* mallocResult[MAXTRY];
uint32_t freeHeap = ESP.getFreeHeap();
void setup() {
Serial.begin(74880);
WiFi.mode(WIFI_OFF);
Serial.printf("free heap at start: %lu\n", freeHeap);
delay(100);
while (counter < MAXTRY)
{
noInterrupts();
maxBlockBefore[counter] = ESP.getMaxFreeBlockSize(); // before 1st try
mallocResult[counter] = malloc(maxBlockBefore[counter] - counter);
maxBlockAfter[counter] = ESP.getMaxFreeBlockSize(); // after 1st try
interrupts();
if (mallocResult[counter])
break;
counter++;
}
for (auto i = 0; i <= counter; ++i)
{
Serial.printf("try %d: before: %u, malloc(%u): %s, after: %u\n", i, maxBlockBefore[i], maxBlockBefore[i] - i, mallocResult[i] ? "ok" : "fail", maxBlockAfter[i]);
}
}
void loop()
{
delay(100);
} The output is
Still, it only succeeds, if I
To me, it looks like this overhead is 4 bytes ;-)
I'm sure, that most people would agree, that
I'm fiddeling with code for an FTP server and was thinking - naively - I could use that |
4 bytes is correct, but it is the overhead in your case. There are other cases, such as building with umm poison. |
BTW, #1183 proposes an ftp lib. |
While this is informative, I think the only bug here is "getMaxFreeBlockSize needs to subtract (epsilon)", no? Allocating the returned value should work (assuming no other allocs happen in between), but is an absolutely awful idea and will make your day a very bad one indeed. |
I'm might repeat myself, but I think |
This project seems a little stale. I forked from that recently and worked on it.
*will not on esp32 although code claims to do so - i just ordered one to test it on that platform... |
I think your link got munged. The displayed URL is good, but the hyperlink doesn't seem to be. Neat work, though! https://github.com/dplasa/esp8266FTPServer
So, in this case, the returned value - 4 or (something else) when in UMM_DEBUG mode. I think we're in agreement on this point, if not on its importance. It is definitely of use in determining how fragmented the system is, and what operations are no longer possible due to fragmentation (i.e. SSL requires 6K heap contiguous and 16.5K receive buffer, also configuous, and I2S can need 2K+ buffers, etc.) However, allocating every single byte available, in an embedded system without MMU and which requires some amount of RAM randomly for binary blob-controlled WiFi connection ops or TCP transfers from the outside world, is going to bring you nothing but headaches when things fall over and die. Please, don't try it if you value your own time... |
OK, I'll surrender! ;-) I am planning to do some cleanups, (most likely make the transfer buffer static or just get rid of it at all), fix the readme. |
Fixes esp8266#7322. Because of UMM internals, the largest `malloc()`able block will be smaller than the largest contiguous free RAM block. Note in the docs.
Fixes #7322. Because of UMM internals, the largest `malloc()`able block will be smaller than the largest contiguous free RAM block. Note in the docs.
Basic Infos
Platform
Settings in IDE
Problem Description
malloc() returns a nullpointer when allocation more than ESP.getMaxFreeBlockSize() - 16 Bytes, whereas the documentation says "ESP.getMaxFreeBlockSize() returns the maximum allocatable ram block regarding heap fragmentation".
Either the documentation should be updated or ESP.getMaxFreeBlockSize() should return a lesser size.
MCVE Sketch
Debug Messages
The text was updated successfully, but these errors were encountered: