Как работает выделение и освобождение памяти.

Тема в разделе "WASM.BEGINNERS", создана пользователем featurelles, 8 янв 2010.

  1. featurelles

    featurelles New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2009
    Сообщения:
    562
    Доброй ночи, меня интересует как СИ (в данном случаи компилятор? ) выделяет память.
    Сейчас не будем вдаваться в объяснения выделения памяти в ОС. А поясните, как компилятор задаёт команду программе освободить какойто участок.

    Вот например. (ничего если я буду использовать функции ядра линекса? от этого суть не меняется..)
    есть структура
    struct test { её тело }
    struct test *test_ptr;
    выделяем память test_ptr = kmalloc(sizeof(struct test) , GFP_ATOMIC );
    Как понимаю компилятор создаёт обращение к ОС запросом на выделение какогото физ. участка памяти, размером sizeof(struct test).. верно?
    затем чтоб освободить этот участок, мы пишеи kfree(test_ptr) тоесть при создании кода компилятор запоминает что указатель test_ptr указывает на структуру размером sizeof(struct test) и генерит код - запрос к ОС о очистке выделенной памяти начиная с адреса test_ptr и размером sizeof(struct test)
    Верно?

    тоесть в рамках одной функции
    Код (Text):
    1. struct test { её тело }
    2. struct test *test_ptr;
    3. выделяем память test_ptr = kmalloc(sizeof(struct test) , GFP_ATOMIC );
    4. kfree(test_ptr);
    Отработает на отлично


    Но, что если разделить запросы на выделение и очистку память в двух разных функциях.
    Код (Text):
    1. struct test {
    2. unsigned char *address_ptr; // тут сохраняем адрес выделенной памяти
    3. element_1;
    4. element_2;
    5. ....
    6. element_n;
    7. }
    8. struct test *test_ptr;
    9.  
    10. int main()
    11. {
    12. func_malloc();
    13. func_free();
    14. }
    15.  
    16. func_malloc()
    17. {
    18.    test_ptr = kmalloc(sizeof(struct test) , GFP_ATOMIC );
    19.    test_ptr->address_ptr =  test_ptr; // сохранили адрес, указывающий на начало выделенной памяти под структуру
    20. }
    21.  
    22.  
    23. func_free()
    24. {
    25.    // тут надо очистить память по адресу занесённому в  test_ptr->address_ptr
    26.   kfree( test_ptr->address_ptr  );
    27. }
    Вопрос таков, как в таком случаи компилятор понемает, сколько нужно очистить байт.
    Или если он этого не понимает, то как сделать, чтоб kfree очистило память по test_ptr->address_ptr размером sizeof(struct test)
     
  2. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Поддержка динамической памяти происходит в рантайме, а не на этапе компиляции. Программа обращается к куче. Куча по необходимости запрашивает у системы память и ведёт учет занятых/свободных блоков.
     
  3. featurelles

    featurelles New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2009
    Сообщения:
    562
    Booster
    А как правильно освободить участок выделенной памяти, начало которой записано в test_ptr->address_ptr и размером sizeof(struct test)
    (выделение памяти в одной функции а её освобождение происходит в другой функции)
     
  4. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    В твоём случае kfree(test_ptr->address_ptr); Размер куча тоже хранит, поэтому достаточно передать указатель. В ядре ядрённая куча, но смысла это не меняет.
     
  5. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Блин, ты же выделял: test_ptr = kmalloc
    Удаляй: free(test_ptr);
     
  6. featurelles

    featurelles New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2009
    Сообщения:
    562
    Мне в коде нужно именно через сохранённый адрес в test_ptr->address_ptr память очищать.
    Сделал очистку так
    kfree((struct test *)test_ptr->address_ptr);
    Вроде после запуска проги, ничего не падает и очистка работает нормально.
     
  7. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Зачем хранить два одинаковых указателя?
     
  8. featurelles

    featurelles New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2009
    Сообщения:
    562
    Booster
    Структуры создаются в N-количестве, и заносятся в двусвязанный список. (первая функция)
    А вторая в выгрузке моего модуля, обходит весь двусвязанный список, проверяет каждую структуру, делает какието действия по копированию и тд.. затем удаляет структуру из двусвязанного списка и делает kfree больше не нужной структуры.

    Я намудрил? и можно просто в kfree передавать указатель на удаляемую структуру? (перед kfree предварительно удалив структуру из двусвязанного списка)
     
  9. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Что занял, то и освобождай.
     
  10. featurelles

    featurelles New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2009
    Сообщения:
    562
    Booster
    Спасибо за ответы.
     
  11. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Куча фиктивно расширяется. Для этого необходимо запрос дать. Стек реально расширяется. Там сторожевые страницы используются. Резервируем сколько нужно памяти. Выделяем страницу в начале этого региона, страницу выше или ниже делаем не доступной(PTE.P и тд). Когда обращение происходит в пределах сторожевой страницы она выделяется, а следующая страница делается сторожевой(менеджер памяти является хэндлером #PF). Ядро вини кроме стека пользователю подобный функционал не даёт, поэтому менеджер памяти необходимо самому ваять. хз как там в линус.
    А компиль совсем к этому отношения не имеет.