[C + +] memory management

Posted by mcubedma on Fri, 04 Feb 2022 07:12:29 +0100

[objectives of this section]
1. C/C + + memory distribution
2. Dynamic memory management in C language
3. Dynamic memory management in C + +
4. operator new and operator delete functions
5. Implementation principle of new and delete
6. Positioning new expression
7. Common interview questions

1. C/C + + memory distribution

Let's first look at the following code and related problems

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";
	const char* pChar3 = "abcd";
	int* ptr1 = (int*)malloc(sizeof(int) * 4);
	int* ptr2 = (int*)calloc(4, sizeof(int));
	int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
	free(ptr1);
	free(ptr3);
}

Exercise:

1. choice question:

  option: A.Stack B.heap C.Data segment(Static area) D.Code snippet(Constant area)

  globalVar Where?__C__  staticGlobalVar Where?__C__

  staticVar Where?__C__  localVar Where?__A__

  num1 Where?__A__

  

  char2 Where?__A__   *char2 Where?_A__

  pChar3 Where?_A___   *pChar3 Where?__D__

  ptr1 Where?__A__    *ptr1 Where?__B__



2. Fill in the blanks: (32-bit program)

  sizeof(num1) = __40__;  

  sizeof(char2) = __5__;   strlen(char2) = __4__;

  sizeof(pChar3) = __4__;   strlen(pChar3) = __4__;

  sizeof(ptr1) = __4__;

[description]

1. Stack is also called stack. Non static local variables / function parameters / return values, etc. stack grows downward.


2. Memory mapping segment is an efficient I/O mapping method, which is used to load a shared dynamic memory library. Users can use the system interface to create shared memory for inter process communication.


3. Heap is used for dynamic memory allocation during program running. Heap can grow up.


4. Storage of static data and global data.


5. Code snippet -- executable code / read-only constant.

2. Dynamic memory management in C language

2.1 malloc/calloc/realloc and free

 

void Test()
{
	int* p1 = (int*)malloc(sizeof(int));
	free(p1);
	// 1. What is the difference between malloc / calloc / realloc?
	int* p2 = (int*)calloc(4, sizeof(int));
	int* p3 = (int*)realloc(p2, sizeof(int) * 10);
	// Do you need free(p2) here?
	free(p3);
}

 malloc:

 

 calloc:

 realloc:

Note: calloc initializes, and all elements are initialized to 0 by byte.

 3. C + + memory management mode

The memory management mode of C language can continue to be used in C + +, but there is nothing to do in some places and it is troublesome to use. Therefore, C + + puts forward its own memory management mode: dynamic memory management through new and delete operators.

3.1 built in type of new / delete operation

void Test()
{
	// Dynamically apply for a space of type int
	int* ptr4 = new int;
	// Dynamically apply for a space of type int and initialize it to 10
	int* ptr5 = new int(10);
	// Dynamically apply for 10 int type spaces
	int* ptr6 = new int[3];
	delete ptr4;
	delete ptr5;
	delete[] ptr6;
}

Note: apply for and release the space of a single element, use the new and delete operators, apply for and release the continuous space, and use new [] and delete []

3.2 user defined types of new and delete operations

 

class Test
{
public:
	Test()
		: _data(0)
	{
		cout << "Test():" << this << endl;
	}
	~Test()
	{
		cout << "~Test():" << this << endl;
	}
private:
	int _data;
};
void Test2()
{
	// Apply for space of a single Test type
	Test* p1 = (Test*)malloc(sizeof(Test));
	free(p1);
	// Apply for 10 Test type spaces
	Test* p2 = (Test*)malloc(sizeof(Test) * 10);
	free(p2);
}

void Test2()
{
	// Apply for a single Test type object
	Test* p1 = new Test;
	delete p1;
	// Apply for 10 Test type objects
	Test* p2 = new Test[10];
	delete[] p2;
}

Note: when applying for a custom type space, new will call the constructor, delete will call the destructor, but malloc and free will not.

 4. operator new and operator delete functions

4.1 operator new and operator delete functions (key points)

New and delete are operators that users can apply for and release dynamic memory. Operator new and operator delete are global functions provided by the system. New calls operator new global function to apply for space at the bottom, and delete releases space through operator delete global function at the bottom.

/*
operator new: This function actually applies for space through malloc. When malloc successfully applies for space, it returns directly; Failed to apply for space,
Try to implement the response measures for insufficient space. If the response measures are set by the user, continue to apply, otherwise throw exceptions.
*/
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
			// If the memory application fails, bad will be thrown here_ Alloc type exception
			static const std::bad_alloc nomem;
			_RAISE(nomem);
		}
	return (p);
}
/*
operator delete: This function finally frees up space through 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;
}
/*
free Implementation of
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)

Through the implementation of the above two global functions, it is known that operator new actually applies for space through malloc. If malloc successfully applies for space, it will return directly. Otherwise, the response measures for insufficient space provided by the user will be implemented. If the user provides this measure, it will continue to apply, otherwise it will throw an exception. operator delete finally frees up space through free.

4.2 class specific overloading of operator new and operator delete (understand)

The following code demonstrates that the ListNode of the linked list node can use the memory pool to apply for and release memory and improve efficiency by overloading the exclusive operator new/ operator delete of the class.

 

struct ListNode
{
	ListNode* _next;
	ListNode* _prev;
	int _data;
	void* operator new(size_t n)
	{
		void* p = nullptr;
		p = allocator<ListNode>().allocate(1);
		cout << "memory pool allocate" << endl;
		return p;
	}
	void operator delete(void* p)
	{
		allocator<ListNode>().deallocate((ListNode*)p, 1);
		cout << "memory pool deallocate" << endl;
	}
};
class List
{
public:
	List()
	{
		_head = new ListNode;
		_head->_next = _head;
		_head->_prev = _head;
	}
	~List()
	{
		ListNode* cur = _head->_next;
		while (cur != _head)
		{
			ListNode* next = cur->_next;
			delete cur;
			cur = next;
		}
		delete _head;
		_head = nullptr;
	}
private:
	ListNode* _head;
};
int main()
{
	List l;
	return 0;
}

5. Implementation principle of new and delete

5.1 built in type

If you apply for a built-in space, new is basically similar to malloc, delete and free. The difference is that new/delete applies for and releases the space of a single element, new [] and delete [] apply for continuous space, and new throws an exception when the application fails, and malloc returns NULL.

5.2 custom types

  • Principle of new

      1. Call the operator new function to apply for space

      2. Execute the constructor on the applied space to complete the construction of the object

  • Principle of delete

        1. Execute the destructor in space to clean up the resources in the object
        2. Call the operator delete function to free up the space of the object

  • Principle of new T[N]

        1. Call the operator new [] function, and actually call the operator new function in operator new [] to complete the application of N object spaces
        2. Execute the constructor N times on the requested space

  • Principle of delete []

        1. Execute the destructor N times on the released object space to clean up the resources in N objects
        2. Call operator delete[] to release the space, and actually call operator delete in operator delete[] to release the space.

 6. Positioning new expression (placement new) (understand)

The positioning new expression is to initialize an object in the allocated original memory space by calling the constructor.


Use format:
New (place_address) type or new (place_address) type (initializer list)
place_address must be a pointer, and initializer list is the initialization list of type

Usage scenario:
In practice, the new positioning expression is generally used in conjunction with the memory pool. Because the memory allocated by the memory pool is not initialized, if it is an object of user-defined type, you need to use the definition expression of new to display and call the constructor to initialize.

 

class Test
{
public:
	Test()
		: _data(0)
	{
		cout << "Test():" << this << endl;
	}
	~Test()
	{
		cout << "~Test():" << this << endl;
	}
private:
	int _data;
};
void Test()
{
	// pt now points to only a space of the same size as the Test object, which can not be regarded as an object because the constructor does not execute
	//that 's ok
	Test* pt = (Test*)malloc(sizeof(Test));
	new(pt) Test; // Note: if the constructor of Test class has parameters, you need to pass parameters here
}

7. Common interview questions
7.1 differences between malloc / free and new/delete

malloc/free and new/delete have something in common: they both request space from the heap and need to be released manually by the user. The differences are:

1. malloc and free are functions, and new and delete are operators
2. The space requested by malloc will not be initialized, but new can be initialized
3. When malloc applies for space, it needs to manually calculate the space size and pass it. new only needs to keep up with the space type
4. The return value of malloc is void *, which must be forcibly rotated when used. New is not required, because new is followed by the type of space
5. When malloc fails to apply for space, it returns NULL, so it must be NULL when using. New does not need it, but new needs to catch exceptions
6. When applying for a custom type object, malloc/free will only open up the space and will not call the constructor and destructor, while new will call the constructor to initialize the object after applying for the space, and delete will call the destructor to clean up the resources in the space before releasing the space

7.2 memory leakage

7.2.1 what is memory leakage and the harm of memory leakage

What is a memory leak: a memory leak is a condition in which a program fails to release memory that is no longer in use due to negligence or error. Memory leakage does not mean the physical disappearance of memory, but the loss of control over a certain section of memory due to design errors after the application allocates it, resulting in a waste of memory.
Harm of memory leakage: long-term running programs have memory leakage, which has a great impact, such as operating system, background services, etc. memory leakage will lead to slower and slower response and finally get stuck.

 

void MemoryLeaks()
{
	// 1. The memory has applied for forgetting to release
	int* p1 = (int*)malloc(sizeof(int));
	int* p2 = new int;
	// 2. Abnormal safety problems
	int* p3 = new int[10];
	Func(); // Here, the Func function throws an exception, causing delete[] p3 not to be executed and p3 not to be released
	delete[] p3;
}

Topics: C++ Back-end