1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-29 05:21:37 +03:00

umm_malloc manual merge with upstream (#7337)

* umm_malloc manual merge with upstream

* Fix divide by zero, case when heap is 100% allocated.

* Removed extra line.

* Fixed block count for debug build. This resolves OOM events for debug build.
Correct overstepping array when freeing.

* Handle another corner case in example HeapMetric.ino.
Comment corrections.

* Revert - ESP.getMaxFreeBlockSize() is back to indicating the size of a
contiguous block of memory before the umm_malloc overhead is removed.

* Stale code cleanup and comment improvements
This commit is contained in:
M Hightower
2020-06-07 20:00:15 -07:00
committed by GitHub
parent 0d04124b94
commit 83523c0259
12 changed files with 572 additions and 245 deletions

View File

@ -3,6 +3,7 @@
// released to public domain
#include <ESP8266WiFi.h>
#include <umm_malloc/umm_malloc.h>
void stats(const char* what) {
// we could use getFreeHeap() getMaxFreeBlockSize() and getHeapFragmentation()
@ -21,9 +22,53 @@ void tryit(int blocksize) {
void** p;
int blocks;
// heap-used ~= blocks*sizeof(void*) + blocks*blocksize
blocks = ((ESP.getMaxFreeBlockSize() / (blocksize + sizeof(void*))) + 3) & ~3; // rounded up, multiple of 4
/*
heap-used ~= blocks*sizeof(void*) + blocks*blocksize
This calculation gets deep into how umm_malloc divides up memory and
understanding it is not important for this example. However, some may find
the details useful when creating memory restricted test cases and possibly
other manufactured failures.
Internally the umm_malloc works with memory in 8-byte increments and aligns
to 8 bytes. The creation of an allocation adds about 4-bytes of overhead
plus alignment to the allocation size and more for debug builds. This
complicates the calculation of `blocks` a little.
ESP.getMaxFreeBlockSize() does not indicate the amount of memory that is
available for use in a single malloc call. It indicates the size of a
contiguous block of (raw) memory before the umm_malloc overhead is removed.
It should also be pointed out that, if you allow for the needed overhead in
your malloc call, it could still fail in the general case. An IRQ handler
could have allocated memory between the time you call
ESP.getMaxFreeBlockSize() and your malloc call, reducing the available
memory. In this particular sketch, with "WiFi off" we are not expecting this
to be an issue.
The macro UMM_OVERHEAD_ADJUST provides a value that can be used to adjust
calculations when trying to dividing up memory as we are here. However, the
calculation of multiple elements combined with the rounding up for the
8-byte alignment of each allocation can make for some tricky calculations.
*/
int rawMemoryMaxFreeBlockSize = ESP.getMaxFreeBlockSize();
// Remove the space for overhead component of the blocks*sizeof(void*) array.
int maxFreeBlockSize = rawMemoryMaxFreeBlockSize - UMM_OVERHEAD_ADJUST;
// Initial estimate to use all of the MaxFreeBlock with multiples of 8 rounding up.
blocks = maxFreeBlockSize /
(((blocksize + UMM_OVERHEAD_ADJUST + 7) & ~7) + sizeof(void*));
/*
While we allowed for the 8-byte alignment overhead for blocks*blocksize we
were unable to compensate in advance for the later 8-byte aligning needed
for the blocks*sizeof(void*) allocation. Thus blocks may be off by one count.
We now validate the estimate and adjust as needed.
*/
int rawMemoryEstimate =
blocks * ((blocksize + UMM_OVERHEAD_ADJUST + 7) & ~7) +
((blocks * sizeof(void*) + UMM_OVERHEAD_ADJUST + 7) & ~7);
if (rawMemoryMaxFreeBlockSize < rawMemoryEstimate) {
--blocks;
}
Serial.printf("\nFilling memory with blocks of %d bytes each\n", blocksize);
stats("before");
@ -41,7 +86,7 @@ void tryit(int blocksize) {
}
stats("freeing every other blocks");
for (int i = 0; i < blocks; i += 4) {
for (int i = 0; i < (blocks - 1); i += 4) {
if (p[i + 1]) {
free(p[i + 1]);
}