实现mbedtls和xTaskCreate()导致ESP32(Arduino IDE)内存泄漏



所以我有下面的代码。如果我在loopTask中直接调用signKey()函数,那么空闲堆是稳定的。然而,如果我使用该函数来使用xTaskCreate()创建任务,那么空闲堆总是在减少。我是不是错过了什么?

以下是使用直接调用的串行监视器上的输出:

FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312

以下是使用任务的串行监视器的输出:

FreeHeap: 338364
FreeHeap: 337776
FreeHeap: 337228
FreeHeap: 336632
FreeHeap: 336080
FreeHeap: 335508
FreeHeap: 334960
FreeHeap: 334372
FreeHeap: 333812
FreeHeap: 333220
FreeHeap: 332672
FreeHeap: 332108
FreeHeap: 331552
FreeHeap: 330964
FreeHeap: 330416
FreeHeap: 329856
FreeHeap: 329304
FreeHeap: 328716
FreeHeap: 328152

这是代码:

#include "mbedtls/pk.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
static String privateKey = "-----BEGIN PRIVATE KEY-----nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCID48Vp/9ydCMUnzZ4n4iQ6pzr6eK+VCL7LcpY8j/tBwLWk3jZ3ETmMm6Ua4MhUMc3ABN84uz0RgDi9nb4RhOUy2SVbvfm5WZhlvpPmDD0yeTgWEyM3h3fBYPnRzMn/6KjsmCUgcfTWjdA+Cnj9vTL41j7bVCkU0/glBh5Rk3rKeImeX/lf4KfstguvJ+OlznCn039+tDlsCNrRgwni+L2AeI4UDZEDGWYRbONzU2WgJ11fr9J+Y6rSCwommDcxhdTtdlorZj2CFEtxRp5nFCDm6Tvu0+aur8zpuhC+NFUWmYEHxztz18X1I4Pcy5cJpuqKL5t/Hxy5Yu7y32EknE8DZv1DFAgMBAAECggEBAIBF+uW13tSuvSwttf9v6iwJ4UamZRKijg4MV6t9KqoQn3q8yeDLE4Ha5fmzaosMNuSZg8XnwvGA1fEjMTAfFF5d7iSR9E9UMqMpixIFU+Sz9n7aIEFmXs8VygdPTuFU1qZx0y/vMs8FbLYpv6uIpfeHNPdeXuSt+nIdVJQf8FHWVgnH7EJHJPCh0SoQZHQhV0M/n7K6iacXdC2k4AW2f2KtwPBOV19S+4Ymq7S6ycIyghdnmMzMhWLgZYoPycMYQRDErEZOSHQHs+BqvKYqp/UVJNKAVihiqYXHmT8hnWMaaj8dnQzVmcsq7dZO7vX+0Zfjd+krj9gbpCG30ESeNOx5sLAECgYEA0wDiGFyFAu6fVhm5np4pHhGhFK765Ys3b5bapEgD1uN92BttPat2Qj11TKGdAERa8X0uuBB8McGcWUcvVnFUIKYE0qj4k/oo7OEw5KmrQVlQLsWv4rls8XTEJcUnoq2lCTXZEfuwEJFBkk4BkbnhioZE3CU0cV/Jg78vl37SJZbE4ECgYEApRNmRPCDWH8Jeo7OSqgee8Qy46R+JpBbnmaaQ9dCO8pp5MYLQSA4C4BeHEpKq4v6C3HL7gf+Z6N/6/WU1X1bqDtXPdito5ZxcnQ0Sa6URIPu7/txNU4Nc4GOfB6nG0/bxiQRDkxf7Kwk2E8xpmoCAQwDhg58Y1k61qnO/iTjIJOj0UCgYEAo7yDtrPU47mYG5BK6R/871qakp+l7G4ivddIy5fDFnsRc7CrnqBnXG+knpqq4pIooEyr/FmOhm3fjcgXijGR6+M/ovwmaP+LhNxhX/ETSmpdyIgoqneRSq15qHWdlDd7YfJPSA0vSyvs3kN6JEIZB5dQRf94hyam4m4vK7FFDYzAECgYEAnlBiva7ILZF20d0ufL8NcddUzgp+UvaxNQa/55U7SsDx99jlR+xL26WyyNat3vGZxnqK1PjvVtc0tete8SzxH+soiHs5CGb1i0PXVTNWuZFTz+FZU2VPFA1rc1dcvFgM59np7osRKWt6lv5ptBMueOKo6jw538fmfm+kUcVuL0/FbECgYBx9ADNvyUaPq/3rQEan4Nzp+yyBL8r7iguLvI8EAYbCil9lACL+xXtScQ7mCY8EW8D8w/0cqA3Wjamb5ntSn4T9Id1Iqq6MvzgJlTjNAYrsgoEC+fmU8iPnHNjxXrf74j4Mlh9pm5j6yeYsHQnMInv60FP7rcRiL2XnDJ5/ev/BWXaQ==n-----END PRIVATE KEY-----";
static bool isTask = false;
static bool printSerial = false;
const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
static String base64_encode(const uint8_t *bytesToEncode, uint16_t len) {
String ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (len--) {
char_array_3[i++] = *(bytesToEncode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; (i < 4); i++) {
ret += base64_chars[char_array_4[i]];
}
i = 0;
}
}
if (i) {
for (j = i; j < 3; j++) {
char_array_3[j] = '';
}
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++) {
ret += base64_chars[char_array_4[j]];
}
}
return ret;
}
static String base64_encode(String str) {
return base64_encode((const unsigned char *) str.c_str(), str.length());
}
uint8_t buffer[2000];
static void signKey(void *parameter) {
String header = "{"typ":"JWT","alg":"RS256"}";
String payload = "{"payload":"my-payload"}";
String content = base64_encode(header) + "." + base64_encode(payload);
mbedtls_pk_context pk_context;
mbedtls_pk_init(&pk_context);
int rc = mbedtls_pk_parse_key(&pk_context, (uint8_t*)privateKey.c_str(), privateKey.length() + 1, NULL, 0);
if (rc != 0) {
mbedtls_pk_free(&pk_context);
if (printSerial)Serial.println("Failed to parse private key (err_code: 0x" + String(rc, HEX) + ")");
if (isTask)vTaskDelete(NULL);
}
mbedtls_entropy_context entropy;
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ctr_drbg_init(&ctr_drbg);
const char* pers = "firebase-jwt";
mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers));
uint8_t digest[32];
rc = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), (uint8_t*)content.c_str(), content.length(), digest);
if (rc != 0) {
mbedtls_pk_free(&pk_context);
mbedtls_entropy_free(&entropy);
mbedtls_ctr_drbg_free(&ctr_drbg);
if (printSerial)Serial.println("Failed to digest content (err_code: 0x" + String(rc, HEX) + ")");
if (isTask)vTaskDelete(NULL);
}
size_t retSize;
rc = mbedtls_pk_sign(&pk_context, MBEDTLS_MD_SHA256, digest, sizeof(digest), buffer, &retSize, mbedtls_ctr_drbg_random, &ctr_drbg);
if (rc != 0) {
mbedtls_pk_free(&pk_context);
mbedtls_entropy_free(&entropy);
mbedtls_ctr_drbg_free(&ctr_drbg);
if (printSerial)Serial.println("Failed to sign content (err_code: 0x" + String(rc, HEX) + ")");
if (isTask)vTaskDelete(NULL);
}
String signature = base64_encode(buffer, retSize);
if (printSerial)Serial.println(signature);
mbedtls_pk_free(&pk_context);
mbedtls_entropy_free(&entropy);
mbedtls_ctr_drbg_free(&ctr_drbg);
if (isTask)vTaskDelete(NULL);
}
void tryTask() {
isTask = true;
xTaskCreate(signKey, "signKey", 4096, NULL, 1, NULL);
}
void tryDirectCall() {
isTask = false;
signKey(NULL);
}
void setup() {
Serial.begin(115200);
}
void loop() {
tryTask();
//tryDirectCall();
Serial.println("FreeHeap: " + String(ESP.getFreeHeap()));
delay(5000);
}

更新:我试图在setup()上创建任务,并使任务连续循环,没有出现空闲堆减少的情况!所以这个问题只存在于我动态创建和删除任务的时候。为什么会发生这种情况?

ESP32有两种类型的内存-数据和指令。Arduino包装器返回了对自由堆的相当自由的解释——查询的cabability MALLOC_CAP_INTERNAL可能包括这两种类型。因此,它可能只是代码缓存被来自一次性线程的垃圾填充。

否则你就漏雨了。无论如何,一次性线程并不是micros上常用的做法——它们会让一切变得更加困难,包括这样的分析。标准方法是在启动时创建一个永久的FreeRTOS任务,并在需要执行某些操作时通过消息队列将工作项传递给它。我可以推荐FreeRTOS教程作为一个优秀的资源。

最新更新