Gestión de memoria C/C++

Distribución de memoria C/C++

En C/C++, se suele considerar que la memoria se divide enárea de montón,área de pila,segmento mapeado en memoria,Área estática (segmento de datos),Área constante (segmento de código)
inserte la descripción de la imagen aquí

  • Las variables globales y las variables estáticas se almacenan en el área estática (segmento de datos).
  • Las variables locales, los parámetros formales, etc. existen en el área de la pila.
  • El espacio liberado por la aplicación dinámica está en el área del montón.
  • Las cadenas de caracteres constantes y similares existen en el área constante.
int globalVar = 1;
//全局变量存在静态区
static int staticGlobalVar = 1;
//全局静态变量存在静态区
void Test()
{
    
    
static int staticVar = 1;
//局部静态变量存在静态区
int localVar = 1;
//局部变量存在栈区
int num1[10] = {
    
     1, 2, 3, 4 };
//整型数组局部变量存在栈区
char char2[] = "abcd";
//字符数组存在栈区,“abcd”常量字符串在常量区
const char* pChar3 = "abcd";
//pChar3局部变量在栈区,“abcd”常量字符串在常量区
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
//ptr1,ptr2,ptr3都是局部变量在栈区,其指向的空间在堆区
free(ptr1);
free(ptr3);
}

Gestión de memoria dinámica en C

  • malloc
    inserte la descripción de la imagen aquí
    El parámetro es el tamaño (bytes) del espacio de memoria que desea abrir, y el valor de retorno es void* y se convierte según sea necesario.
    El espacio asignado no se inicializa.
  • llamar
    inserte la descripción de la imagen aquí
    La función de los dos parámetros es abrir varios espacios requeridos para cada uno (bytes).El
    espacio abierto se inicializa a 0.
    Por ejemplo:
int* a = (int*)calloc(10,sizeof(int));

reasignar
inserte la descripción de la imagen aquí
Ajusta el espacio al que apunta ptr, que puede expandirse o reducirse, pero generalmente se usa para expansión.Si el primer parámetro es un puntero nulo, entonces su función es equivalente a malloc
expansión

  • Expansión en el lugar: Si todavía hay mucho espacio detrás del espacio actual para la expansión, entonces la capacidad se ampliará in situ.
  • Expansión remota: Si no hay suficiente espacio detrás del espacio actual para la expansión de la capacidad, el sistema encontrará un nuevo espacio suficiente, copiará los datos del espacio original al nuevo espacio y liberará el espacio original.
    gratis
    inserte la descripción de la imagen aquí
    Liberar el espacio asignado dinámicamente en el montón

Preguntas para pensar:
4. ¿Cuál es la diferencia entre malloc/calloc/realloc?

malloc y calloc solicitan espacio del área del montón y realloc ajusta el tamaño del espacio original.
Cuando el primer parámetro de realloc es NULL, es equivalente a malloc.
El espacio de la aplicación malloc no se inicializa y el espacio de la aplicación calloc se inicializa.
Cuando la realloc se está expandiendo, existen problemas de expansión en el lugar y expansión fuera del sitio.

Gestión de memoria dinámica en C++

Las funciones de gestión de memoria dinámica en C ya no pueden satisfacer completamente las necesidades de C++, por lo que ha surgido un nuevo método de gestión de memoria dinámica en C++: operadores nuevos y de eliminación para la gestión de memoria dinámica.

nuevo tipo incorporado de operación de eliminación

  • nuevo
int* p1 = new int;
int* p2 = new int[10];

Se puede ver que es muy conveniente usar el operador new para aplicar recursos dinámicos, no hay necesidad de forzar la conversión de tipo, y no hay necesidad de calcular el tamaño del espacio a abrir, otro punto es que no No es necesario comprobar si la apertura es exitosa después de la aplicación.
Después de que malloc no puede solicitar espacio, devuelve un puntero nulo, por lo que debe verificarse después de usar malloc para solicitar recursos, y después de que el nuevo operador no se abre, usa el método de lanzar una excepción, que no necesita ser revisado.

Además, new puede inicializarlo mientras solicita espacio:

int *p1 = new int(6);
int* p2 = new int[6]{
    
    1,2,3,4,5,6};
  • delete
    delete libera el espacio creado por new, y deben usarse juntos, delete corresponde a new delete[ ] corresponde a new [ ], si no se usan juntos, pueden ocurrir problemas (mencionados más adelante).
int* p1 = new int[6];
delete p1;

Esto saldrá mal.

nuevo tipo personalizado de operación de eliminación

class A
{
    
    
public:
    A(int a = 0,int b = 0)
        :_a(a)
        ,_b(b)
    {
    
    
        cout << "A()" << endl;
    }
    ~A()
    {
    
    
        cout << "~A()" << endl;
    }
private:
    int _a;
    int _b;
};
int main()
{
    
    
    A* p = (A*)malloc(sizeof(A));
    if (p == NULL)
    {
    
    
        perror("malloc fail\n");
        exit(-1);
    }
    free(p);
    A* ptr = new A;
    delete ptr;
    return 0;
}

inserte la descripción de la imagen aquí
Se puede ver que malloc y free no llaman al constructor y destructor del tipo personalizado.
inserte la descripción de la imagen aquí
new y delete llaman al constructor y destructor del tipo personalizado.

Entonces new y delete nacen para los tipos personalizados. No hay diferencia entre los tipos incorporados y malloc y free (solo la diferencia en el uso), pero para los tipos personalizados, new llamará al constructor y delete llamará a la función destructora.

El constructor no se puede llamar explícitamente (se puede llamar con posicionamiento nuevo)
El destructor se puede llamar explícitamente
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Operador nuevo y funciones de eliminación de operador

new y delete son operadores para que los usuarios apliquen y liberen memoria dinámica. operator new y operator delete son funciones globales proporcionadas por el sistema. new llama a la nueva función global del operador en la capa inferior para solicitar espacio, y delete usa el operador delete global Función en la capa inferior para liberar espacio.

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
    
    
	// try to allocate size bytes
	void *p;
	while ((p = malloc(size)) == 0)
	if (_callnewh(size) == 0)
	{
    
    
	// report no memory
	// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
	static const std::bad_alloc nomem;
	_RAISE(nomem);
}
	return (p);
}

operator new es una función global que encapsula malloc.Si la aplicación falla, no devolverá un puntero nulo, sino que generará una excepción.

/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void *pUserData)
{
    
    
_CrtMemBlockHeader * pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg( pUserData, pHead->nBlockUse );
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}

operator delete también es una función global, que es la encapsulación de free.

Principio de implementación de nuevo y eliminar

  • nuevo
    1, llame al operador nuevo para solicitar el espacio
    2, llame al constructor
  • new [ ]
    1. Llamar a la función operador new[ ] es llamar a la función operador new varias veces para solicitar espacios múltiples
    2. Llamar al constructor varias veces
  • eliminar
    1. Llame al destructor en el espacio solicitado para limpiar el objeto.
    2. Llame a la función de eliminación del operador para liberar el espacio solicitado
  • delete[ ]
    1. Llame al destructor varias veces en el espacio solicitado para limpiar el objeto.
    2. Llamar a la eliminación del operador [ ] es llamar a la función de eliminación del operador para liberar espacio.

¿Por qué dice que new delete new[] delete[] malloc free debe usarse en conjunto? El siguiente ejemplo es suficiente para demostrarlo:
Dígame, ¿cómo se implementan new[ ] y delete[ ]?

int* p1 = new int[6];

[6] le indicará al compilador que solicite 6 espacios de tamaño int y complete 6 llamadas al constructor.

delete[] p1;

delete[ ] no especifica como liberar el espacio de varios objetos y llamar varias veces al destructor ¿Cómo lo hace?
De hecho, cuando se usa new [ ], el compilador hará algunas operaciones pequeñas para permitirle abrir 4 bytes más de espacio para almacenar y abrir espacio para varios objetos para que los use delete [ ].
inserte la descripción de la imagen aquí
Si usa eliminar o liberar para liberar este espacio en este momento, se informará un error, porque no se permite liberar el espacio abierto dinámicamente desde la parte central. Y debido a que el destructor solo se llamará una vez, la limpieza no se puede realizar para todos los objetos.

class A
{
    
    
public:
    A(int a = 0,int b = 0)
        :_a(a)
        ,_b(b)
    {
    
    
        cout << "A()" << endl;
    }
    ~A()
    {
    
    
        cout << "~A()" << endl;
    }
private:
    int _a;
    int _b;
};
int main()
{
    
    
    A* ptr1 = new A[6];
    delete ptr1;
    return 0;
}

inserte la descripción de la imagen aquí

Localización del uso de nuevos

Como se mencionó anteriormente, cuando malloc opera un tipo personalizado, no se llamará al constructor y el método de localización de new puede mostrar la llamada al constructor.

class A
{
    
    
public:
    A(int a = 0,int b = 0)
        :_a(a)
        ,_b(b)
    {
    
    
        cout << "A()" << endl;
    }
    ~A()
    {
    
    
        cout << "~A()" << endl;
    }
private:
    int _a;
    int _b;
};
int main()
{
    
    
    A* ptr = (A*)operator new(sizeof(A));
    new(ptr)A(2, 3);
    return 0;
}

inserte la descripción de la imagen aquí
Después de localizar nuevo
inserte la descripción de la imagen aquí
Esto es solo por ejemplo, localizar nuevo generalmente se usa con el grupo de memoria.Debido a que la memoria asignada por el grupo de memoria no se inicializa, si es un objeto de un tipo personalizado, debe usar la expresión de definición de nuevo para llamar explícitamente al constructor para la inicialización.

Supongo que te gusta

Origin blog.csdn.net/Djsnxbjans/article/details/129538892
Recomendado
Clasificación