ARM GCC куча не полностью используется - PullRequest
0 голосов
/ 16 декабря 2018

Я настраиваю свою платформу Cortex-M4 для использования кучи памяти и сталкиваюсь с некоторыми проблемами.Я установил размер области кучи равным 512 байтам, и он выделяет только 9 байт.Затем я установил кучу равной 10 КБ, и она может выделить только 362 байта.Вот моя заглушка gcc:

int _sbrk(int a)
{
    //align a to 4 bytes
    if (a & 3)
    {
        a += (4 - (a & 0x3));
    }

    extern long __heap_start__;
    extern long __heap_end__;
    static char* heap_ptr = (char*)&__heap_start__;

    if (heap_ptr + a < (char*)&__heap_end__)
    {
        int res = (int)heap_ptr;
        heap_ptr += a;
        return res;
    }
    else
    {
        return -1;
    }
}

__heap_start__ и __heap_end__ верны, и их различие показывает правильный размер области.Я добавил отладку в функцию _sbrk, чтобы посмотреть, какой аргумент a передается при вызове этой функции, и значения этого аргумента аналогичны этим при каждом вызове соответственно:

2552
1708
4096

Что я могу сделать, чтобызаставить его использовать полную память кучи?А как рассчитывается _sbrk аргумент?По сути, что здесь не так?

Сборка кода C ++ с использованием new (std::nothrow).

EDIT Если я использую malloc (стиль C), он выделяет 524 байта инет _sbrk вызова перед основным, в отличие от использования operator new.

arm-none-eabi-g++.exe (GNU Tools for ARM Embedded Processors 6-2017-q2-update) 6.3.1 20170620 (release) [ARM/embedded-6-branch revision 249437]
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

EDIT2 Пример минимального завершения проверки
Вот мой код приложения и _sbrk с печатью информации:

void foo()
{
    while (true)
    {
        uint8_t * byte = new (std::nothrow) uint8_t;
        if (byte)
        {
            DBB("Byte allocated");
            cnt++;
        }
        else
        {
            DBB_ERROR("Allocated %d bytes", cnt);
        }
    }
}

int _sbrk(int a)
{
    //align a to 4 bytes
    if (a & 3)
    {
        a += (4 - (a & 0x3));
    }

    extern long __heap_start__;
    extern long __heap_end__;
    static char* heap_ptr = (char*)&__heap_start__;

    DBB("%d 0x%08X", a, a);
    DBB("0x%08X", heap_ptr);
    DBB("0x%08X", &__heap_start__);
    DBB("0x%08X", &__heap_end__);

    if (heap_ptr + a < (char*)&__heap_end__)
    {
        int res = (int)heap_ptr;
        heap_ptr += a;
        DBB("OK 0x%08X 0x%08X", res, heap_ptr);
        return res;
    }
    else
    {
        DBB("ERROR");
        return -1;
    }
}

И произведенная продукция:

enter image description here

1 Ответ

0 голосов
/ 16 декабря 2018

Ваш вывод показывает, что система выделения памяти C ++ сначала запрашивает 32 байта, а затем 132 байта.Затем он может удовлетворить девять запросов на new uint8_t с этим пространством.Предположительно он использует некоторые из 164 байтов для внутреннего учета.Это может включать ведение списков ссылок или карт распределения блоков или какой-либо другой структуры данных.Кроме того, для эффективности он, скорее всего, не отслеживает однобайтовые распределения, а обеспечивает некоторый минимальный размер блока для каждого распределения, возможно, 8 или 16 байтов.Когда ему не хватает места, в котором он нуждается, он запрашивает еще 4096 байт.Затем ваш sbrk завершается сбоем, поскольку он недоступен.

Система выделения памяти C ++ работает в соответствии с проектами.Для работы требуется больше места, чем выделено для индивидуальных запросов.Чтобы предоставить больше памяти для запросов, вы должны предоставить больше памяти в куче.Вы не можете ожидать однозначного соответствия или любого простого соответствия между памятью, предоставленной из sbrk в систему выделения памяти, и памятью, предоставленной из системы выделения памяти ее клиентам.

Нет никакого способасказать системе выделения памяти C ++ использовать «полную память кучи» для удовлетворения запросов к ней.Требуется отслеживать динамические распределения и освобождения памяти.Поскольку его клиенты могут отправлять запросы разного размера и освобождать их в любом порядке, ему необходимо иметь возможность отслеживать, какие блоки в настоящее время выделены, а какие нет - простого стека будет недостаточно.Следовательно, он должен использовать дополнительные структуры данных для отслеживания памяти, и эти структуры данных будут занимать пространство.Таким образом, не все пространство кучи может быть предоставлено клиентам;некоторые из них должны использоваться для накладных расходов.

Если использование памяти системой выделения памяти в вашей реализации C ++ слишком неэффективно для ваших целей, вы можете заменить ее той, которую вы пишете сами, или сторонним программным обеспечением.,Любая реализация системы выделения памяти делает различные компромиссы в отношении скорости и размера блока, и они могут быть адаптированы к конкретным ситуациям и целям.

...