No time -nginx array structure

Nginx encapsulates common arrays, linked lists, and queues to make the main business logic clearer.

An array of

In Nginx arrays, memory allocation is based on the memory pool, and is not fixed, nor as much memory as required. If the current memory is insufficient to store the required elements, the memory allocation is twice the size of the current array, which reduces the number of memory allocation and improves efficiency. Many languages have this feature, such as Java, which encapsulates array expansion.

Nginx’s modular code makes it easier to read. Arrays are wrapped in core/ngx_array.h:

Array structure

struct ngx_array_s {
    void        *elts;
    ngx_uint_t   nelts;
    size_t       size;
    ngx_uint_t   nalloc;
    ngx_pool_t  *pool;
};
Copy the code
  • *elts: points to the first address of the array data area
  • nelts: The actual number of data in the array
  • size: Size in bytes occupied by a single element
  • nalloc: Array capacity
  • *pool: Memory pool where array objects reside

So let’s look at some methods for arrays:

ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);
void ngx_array_destroy(ngx_array_t *a);
void *ngx_array_push(ngx_array_t *a);
void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
Copy the code
  • *ngx_array_create: Creates a new dynamic array
  • ngx_array_destroy: Destroys the array object and the memory is reclaimed by the memory pool
  • *ngx_array_push: Adds a new element to an existing array
  • *ngx_array_push_n: Adds n new elements to the existing array

Array methods

ngx_array_create

In the file core/ngx_array.c, note the source version nginx-0.5

ngx_array_t *
ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
{
    ngx_array_t *a;

    // Allocate a dynamic array header
    a = ngx_palloc(p, sizeof(ngx_array_t));
    if (a == NULL) {
        return NULL;
    }

    // Assign n sizes to the first address of the array
    a->elts = ngx_palloc(p, n * size);
    if (a->elts == NULL) {
        return NULL;
    }

    // The actual number of elements
    a->nelts = 0;
    // Element size
    a->size = size;
    / / capacity
    a->nalloc = n;
    / / memory pool
    a->pool = p;

    return a;
}
Copy the code

Creating an array:

  • First we allocate the array header
  • The array data area is then allocated, both times in the passed memory pool (the memory pool pointed to by pool).
  • It then simply initializes the array header and returns its starting position.

Small tips:

Sizeof :sizeof is a C unary operator, such as ++ and –, that returns the sizeof an object or type in bytes

Therefore, it is not a function. The sizeof operator gives the storage sizeof its operands in bytes.

  1. An operand can be an expression or a type name enclosed in parentheses.
  2. The storage size of the operand is determined by its type.

Sizeof, sizeof, sizeof, sizeof

sizeof( object ); // sizeof(object);
sizeof( type_name ); // sizeof( 类型 );
sizeof object; // sizeof objects;
Copy the code

The sizeof operator results in size_t, which is defined in the header as typedef unsigned int size_t. This type is guaranteed to hold the size in bytes of the largest object created by the implementation.

Sizeof’s main uses:

  1. Used when allocating memory
  2. Used when counting the number of elements in an array

ngx_array_destroy

Create and destroy, unlike Java, which has object garbage collection

void
ngx_array_destroy(ngx_array_t *a)
{
    ngx_pool_t  *p;

    p = a->pool;

    // Move the last pointer to the pool to free the memory occupied by all elements of the array
    if ((u_char *) a->elts + a->size * a->nalloc == p->last) {
        p->last -= a->size * a->nalloc;
    }

    // Free the memory occupied by the first pointer of the array
    if ((u_char *) a + sizeof(ngx_array_t) == p->last) { p->last = (u_char *) a; }}Copy the code

The last pointer of the memory pool is actually destroyed. That is, the memory of the array is reclaimed by the memory pool without calling free or other operations to free the memory.

ngx_array_push

void *
ngx_array_push(ngx_array_t *a)
{
    void        *elt, *new;
    size_t       size;
    ngx_pool_t  *p;

    // Check if the array is full
    // nlelts: the actual number of elements
    / / nalloc: capacity
    if (a->nelts == a->nalloc) {

        /* the array is full */

        // Calculate the size of memory occupied by all elements of the array
        size = a->size * a->nalloc;

        p = a->pool;

        if ((u_char *) a->elts + size == p->last && p->last + a->size <= p->end)
        {
            // The current memory pool can hold at least one element
            /* * the array allocation is the last in the pool * and there is space for new allocation */

            p->last += a->size;
            a->nalloc++;

        } else {
            // If the current memory pool is insufficient to hold an element, new array memory is allocated
            /* allocate a new array */

            // From here you can see 2 times
            new = ngx_palloc(p, 2 * size);
            if (new= =NULL) {
                return NULL;
            }

            // Copy or copy
            ngx_memcpy(new, a->elts, size);
            a->elts = new;
            a->nalloc *= 2;
        }
    }

    elt = (u_char *) a->elts + a->size * a->nelts;
    a->nelts++;

    return elt;
}
Copy the code

ngx_array_push_n

void *
ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
{
    void        *elt, *new;
    size_t       size;
    ngx_uint_t   nalloc;
    ngx_pool_t  *p;

    size = n * a->size;

    if (a->nelts + n > a->nalloc) {

        /* the array is full */

        p = a->pool;

        if ((u_char *) a->elts + a->size * a->nalloc == p->last
            && p->last + size <= p->end)
        {
            /* * the array allocation is the last in the pool * and there is space for new allocation */

            p->last += size;
            a->nalloc += n;

        } else {
            /* allocate a new array */

            nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc);

            new = ngx_palloc(p, nalloc * a->size);
            if (new= =NULL) {
                return NULL;
            }

            ngx_memcpy(new, a->elts, a->nelts * a->size);
            a->elts = new;
            a->nalloc = nalloc;
        }
    }

    elt = (u_char *) a->elts + a->size * a->nelts;
    a->nelts += n;

    return elt;
}
Copy the code

There are two operations to add elements to an array, ngx_array_push and ngx_array_PUSH_n, which add one and more elements, respectively. The actual adding is not done in either of these functions. It is done by applying for the required memory space for the element, returning the first address to the memory space, and adding the element in the form of pointer assignment.

Write a test case:

The test code is as follows:

#include "ngx_config.h"
#include <stdio.h>
#include "ngx_conf_file.h"
#include "nginx.h"
#include "ngx_core.h"
#include "ngx_string.h"
#include "ngx_palloc.h"
#include "ngx_array.h"

volatile ngx_cycle_t *ngx_cycle;

void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log.ngx_err_t err,
                        const char *fmt, ...)
{}void dump_array(ngx_array_t *a)
{
    if (a)
    {
        printf("array = 0x%x\n", a);
        printf(" .elts = 0x%x\n", a->elts);
        printf(" .nelts = %d\n", a->nelts);
        printf(" .size = %d\n", a->size);
        printf(" .nalloc = %d\n", a->nalloc);
        printf(" .pool = %d\n", a->pool);

        printf("elements: ");
        int *ptr = (int *)(a->elts);
        for (; ptr < (int *)(a->elts + a->nalloc * a->size);)
        {
            printf("%d ", *ptr++);
        }
        printf("\n"); }}int main(a)
{
    ngx_pool_t *pool;
    int i;

    printf("------------\n");
    printf("create a new pool: \n");
    printf("------\n");
    pool = ngx_create_pool(1024.NULL);

    printf("------------\n");
    printf("alloc an array from the pool: \n");
    printf("------------\n");
    ngx_array_t *a = ngx_array_create(pool, 5.sizeof(int));

    for (i = 0; i < 5; i++)
    {
        int *ptr = ngx_array_push(a);
        *ptr = 2 * i;
    }

    dump_array(a);

    ngx_array_destroy(a);
    ngx_destroy_pool(pool);
    return 0;
}
Copy the code

Write one

CXX = GCC CXXFLAGS + = - g - Wall - Wextra NGX_ROOT = / Users/mf/Documents/mysource/nginx - 0.5 the TARGETS = ngx_array_t_test TARGETS_C_FILE= $(TARGETS).c CLEANUP = rm-f $(TARGETS) *.o all:$(TARGETS) clean: $(CLEANUP) CORE_INCS =-I. \ -I$(NGX_ROOT)/src/core \ -I$(NGX_ROOT)/src/event \ -I$(NGX_ROOT)/src/event/modules \ -I$(NGX_ROOT)/src/os/unix \ -I$(NGX_ROOT)/objs \ NGX_PALLOC =$(NGX_ROOT)/objs/src/core/ngx_palloc.o NGX_STRING =$(NGX_ROOT)/objs/src/core/ngx_string.o NGX_ALLOC =$(NGX_ROOT)/objs/src/os/unix/ngx_alloc.o NGX_ARRAY =$(NGX_ROOT)/objs/src/core/ngx_array.o $(TARGETS):$(TARGETS_C_FILE) $(CXX) $(CXXFLAGS) $(CORE_INCS) $(NGX_PALLOC) $(NGX_STRING) $(NGX_ALLOC) $(NGX_ARRAY) $^ -o$@

Copy the code

Terminal run make all, then run./ngx_array_t_test

Running results:

↳. / ngx_array_t_test    00:14:46  -- -- -- -- -- -- -- -- -- -- -- -- the create a new pool: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- alloc an array from the pool: ------------ array = 0x74009840 .elts = 0x74009868 .nelts = 5 .size = 4 .nalloc = 5 .pool = 1946195968 elements: 0, 2, 4, 6, 8Copy the code

reference

  • C: sizeof
  • Nginx source code analysis – array structure ngx_array_t
  • Tc. Dreamcat. Ink/archives / 29…