Подтвердить что ты не робот

Память не запрашивается

Я написал простой распределитель памяти, в основном создает цепочку выделенных блоков, они связаны друг с другом с помощью указателей, хранящихся в метаданных struct до выделенной области.

Код работает отлично, и я могу выделить цепочку блоков размером sz, которые затем освобождаются с помощью другой функции, написанной мной.

Проблема в том, что я заметил, используя команду vmmap, что, по-видимому, память выделяется malloc без явного запроса. Здесь вставка различных vmmap, взятых в разных точках выполнения программы:

## before first alloc
# this has been taken before any allocation happens in the code.

REGION TYPE                      VIRTUAL
===========                      =======
Kernel Alloc Once                     4K
MALLOC                             9388K        see MALLOC ZONE table below
MALLOC (admin)                       24K
STACK GUARD                        56.0M
Stack                              8192K
VM_ALLOCATE                           8K <-- we start with 8K
__DATA                              668K
__LINKEDIT                         70.2M
__TEXT                             5860K
shared memory                         4K
===========                      =======
TOTAL                             149.8M

                                 VIRTUAL ALLOCATION      BYTES
MALLOC ZONE                         SIZE      COUNT  ALLOCATED  % FULL
===========                      =======  =========  =========  ======
DefaultMallocZone_0x10ad37000      9216K        363        27K      0%

=======================================================================

## after first alloc
# this is after the chain allocation.

REGION TYPE                      VIRTUAL
===========                      =======
Kernel Alloc Once                     4K
MALLOC                             18.2M <-- why the hell does malloc() increase?
MALLOC (admin)                       24K
STACK GUARD                        56.0M
Stack                              8192K
VM_ALLOCATE                        8200K <-- this is expected, we allocate memory with vm_allocate()
__DATA                              668K
__LINKEDIT                         70.2M
__TEXT                             5860K
shared memory                         4K
===========                      =======
TOTAL                             166.8M

                                 VIRTUAL ALLOCATION      BYTES
MALLOC ZONE                         SIZE      COUNT  ALLOCATED  % FULL
===========                      =======  =========  =========  ======
DefaultMallocZone_0x10ad37000      18.0M        364        31K      0%

=======================================================================

## after chain release

REGION TYPE                      VIRTUAL
===========                      =======
Kernel Alloc Once                     4K
MALLOC                             19.2M <-- malloc increases even more?!?
MALLOC (admin)                       24K
STACK GUARD                        56.0M
Stack                              8192K
VM_ALLOCATE                           8K <-- after chain release
__DATA                              668K
__LINKEDIT                         70.2M
__TEXT                             5860K
shared memory                         4K
===========                      =======
TOTAL                             159.8M <-- but why has total size increased?

                                 VIRTUAL ALLOCATION      BYTES
MALLOC ZONE                         SIZE      COUNT  ALLOCATED  % FULL
===========                      =======  =========  =========  ======
DefaultMallocZone_0x10ad37000      19.0M        364        31K      0%

Я на OS X, и я использую подпрограмму vm_allocate для выделения памяти для моих блоков. Итак, как и ожидалось, раздел vm_allocate в vmmap показывает, что после освобождения цепочки память раздела возвращается к первоначальному размеру, то есть 8K. Я никогда не называю malloc в своем коде.

Но, по-видимому, размер раздела malloc увеличивается после выделения! И он никогда не освобождается. Общий размер после освобождения цепи на 10 МБ больше, чем до распределения цепи.

Кто-нибудь знает, почему это могло случиться? Я не думаю, что процедура vm_allocate вызывает malloc, это не имеет смысла. Заранее благодарим за помощь!

Тестирование без выделения кода

Я действительно прокомментировал весь код выделения, который выполнял моя программа, в основном оставил пустую main функцию. Затем повторили три проверки vmmap для моей программы. Результаты:

REGION TYPE                      VIRTUAL
===========                      =======
Kernel Alloc Once                     4K
MALLOC                             9388K        see MALLOC ZONE table below
MALLOC (admin)                       24K
STACK GUARD                        56.0M
Stack                              8192K
VM_ALLOCATE                           8K
__DATA                              668K
__LINKEDIT                         70.2M
__TEXT                             5860K
shared memory                         4K
===========                      =======
TOTAL                             149.8M

                                 VIRTUAL ALLOCATION      BYTES
MALLOC ZONE                         SIZE      COUNT  ALLOCATED  % FULL
===========                      =======  =========  =========  ======
DefaultMallocZone_0x105379000      9216K        363        27K      0%

=========================================================================

REGION TYPE                      VIRTUAL
===========                      =======
Kernel Alloc Once                     4K
MALLOC                             10.2M        see MALLOC ZONE table below
MALLOC (admin)                       24K
STACK GUARD                        56.0M
Stack                              8192K
VM_ALLOCATE                           8K
__DATA                              668K
__LINKEDIT                         70.2M
__TEXT                             5860K
shared memory                         4K
===========                      =======
TOTAL                             150.8M

                                 VIRTUAL ALLOCATION      BYTES
MALLOC ZONE                         SIZE      COUNT  ALLOCATED  % FULL
===========                      =======  =========  =========  ======
DefaultMallocZone_0x105379000      10.0M        363        27K      0%

=========================================================================

REGION TYPE                      VIRTUAL
===========                      =======
Kernel Alloc Once                     4K
MALLOC                             11.2M        see MALLOC ZONE table below
MALLOC (admin)                       24K
STACK GUARD                        56.0M
Stack                              8192K
VM_ALLOCATE                           8K
__DATA                              668K
__LINKEDIT                         70.2M
__TEXT                             5860K
shared memory                         4K
===========                      =======
TOTAL                             151.8M

                                 VIRTUAL ALLOCATION      BYTES
MALLOC ZONE                         SIZE      COUNT  ALLOCATED  % FULL
===========                      =======  =========  =========  ======
DefaultMallocZone_0x105379000      11.0M        363        27K      0%

vm_allocate область теперь не увеличивается, как и ожидалось, никто не звонит vm_allocate. Но, как вы видите, регион malloc все еще увеличивается! Даже без моего кода. Он растет меньше, чем раньше, то есть 11 МБ вместо 18 МБ.

Это означает, что мой код оказывает прямое влияние на него, но что это может быть? Возможно, функции библиотеки вызываются malloc? Я использую некоторые printf в моем выделенном коде, и я знаю такие функции, как printf call malloc, но почему тогда память не освобождена?

EDIT - добавление кода

Извините, что не включил его раньше, и извините, если это полный беспорядок, я написал это примерно через два часа, и это моя первая попытка создать настраиваемый распределитель.

#include <mach/mach.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc/malloc.h>

#define BLOCK_NO 2048

typedef struct mem_block {
    struct mem_block *next;
    unsigned int sz;
    unsigned int free:1;
} mem_block_t;

void *alloc_block(vm_size_t size)
{
    void *block_addr=NULL;
    mem_block_t metadata;
    vm_address_t *start_addr=0;

    vm_allocate(mach_task_self_, (vm_address_t*)&start_addr, size, 1);
    block_addr=(start_addr);
    metadata.next=(void*)NULL;
    metadata.sz=(unsigned int)size;
    metadata.free=0x0;

    memcpy(block_addr, (mem_block_t*)&metadata, sizeof(mem_block_t));

    return block_addr+sizeof(mem_block_t);
}

void dealloc_block(void *block_addr)
{
    unsigned int sz=0;
    vm_address_t start_addr = (vm_address_t)block_addr-sizeof(mem_block_t);
    memcpy(&sz, (void*)start_addr+sizeof(mem_block_t*), sizeof(sz));
    vm_deallocate(mach_task_self_, start_addr, sz);
}

void *alloc_block_chain(unsigned int blocks, vm_size_t size)
{
    void *head=NULL, *old_block=NULL, *curr=NULL;
    head = alloc_block(size);
    old_block = head;
    for (int i=0; i<blocks-1; i++) {
        curr = alloc_block(size);
        ((mem_block_t*)old_block)->next=curr;
        old_block=curr;
    }

    return head;
}

void dealloc_block_chain(void *block_addr_start)
{
    int cnt=0;
    void *curr=NULL, *old_block=NULL;
    curr=block_addr_start;
    while(1) {
        if (old_block) {
            dealloc_block(old_block);
            malloc_printf("dealloc'd block #%d: %p\n", cnt, old_block);
            cnt++;
        }
        if (!((mem_block_t*)curr)->next) {
            dealloc_block(curr);
            malloc_printf("dealloc'd final block: %p\n", curr);
            break;
        } else {
            old_block = curr;
            curr=((mem_block_t*)curr)->next;
        }
    }
}

int main(int argc, const char * argv[]) {

    system("read -n 1 -s -p \"Press any key to continue...\";echo");

    void *start = alloc_block_chain(BLOCK_NO, PAGE_SIZE);
    void *curr=start;

    for (int i=0; i<BLOCK_NO; i++) {
        malloc_printf("block #%d: %p\n", i, curr);
        curr = ((mem_block_t*)curr)->next;
    }

    system("read -n 1 -s -p \"Press any key to continue...\";echo");

    dealloc_block_chain(start);

    system("read -n 1 -s -p \"Press any key to continue...\";echo");

    return 0;
}

Возможное решение

Вы можете видеть, что я использую malloc_printf в коде. Я ранее называл printf там. Функция malloc_printf похожа на printf, но избегает вызова malloc.

Это, похоже, устраняет утечку! Я буду делать больше тестов позже, но для того, что я видел, проблема действительно может быть реализована в OS X printf.

4b9b3361

Ответ 1

Функция vm_deallocate освобождает область виртуальной памяти в указанном адресном пространстве задачи. Область начинается с начала виртуальной страницы, содержащей адрес и заканчивается в конце виртуальной страницы, содержащей address + size - 1. Из-за этого округления до границ виртуальной страницы объем освобожденной памяти может быть больше, чем размер. Я думаю, что ссылки не будут очищены, и поэтому другие потоки могут ссылаться на это адресное пространство. Если вы запускаете указанную программу постоянно, это может привести к сбою, а также нужно также очистить ссылку. Исправьте меня, если я ошибаюсь.