This is the 10th day of my participation in Gwen Challenge

Don’t miss the back end of the interview

C++ memory management

Today, we will continue to share the knowledge of interview with you

Linux kernel Space, memory management, process management device, driver virtual file system (VFS) The kernel space is protected and users cannot read or write to the kernel space, otherwise a segment error will occur
Environment variable (ENV) PATH
Command line arguments char *agrv[]
The stack area ⬇ ️ Function return address, return value, parameters, local variables
Shared library (mapping area) ⬇️ Call the dynamic library or mmap function for file mapping
Heap area ⬆ ️ Use new/malloc and delete/free to free the chained storage structure
The BSS area Uninitialized global and static variables, as well as global and static variables initialized to 0, are already allocated at compile time
.data area Initialized global and static variables are allocated space at compile time
.text 2. Text area — program code, machine code
0 to 4 k reserves
#include<stdio.h>
 
int a;    // global extent.bss is not initialized
int b=1;    // Global extent.data is initialized
static int c=2;    // Global extent.data is initialized
const int d=3;    // The value of d cannot be modified in the read-only data section, also called the literal constant section ro.data
int main(void)
{
    int e=4;    / / the stack area
    static int f=5;    // Global extents have been initialized
    const int g=6;    // stack area, the value of a variable cannot be changed by its name, but can be changed by its address
    int *p=malloc(sizeof(int))    // The pointer variable p is on the stack, but the 4-byte space it points to is on the heap
    char *str="abcd";    // The string "abcd" contains the literal constant area, and the pointer variable STR is stored in the stack area, which stores the starting address of "abcd"
    return 0;
}
Copy the code

Memory leaks and classification

A memory leak is the failure of a program to release memory that is no longer in use due to negligence or error. A memory leak is not the disappearance of memory at a physical address, but the loss of control over the memory allocated by an application, resulting in a waste of memory.

  • In general, if the memory is not deleted or free after new/malloc, the memory is leaked
  • Valgrind can be used in Linux to detect memory leaks

Memory leak classification:

  • Heap memory leak — no delete/free drop after new/malloc
  • System resource leakage: Resources allocated by the system are not released by specified functions. As a result, system resources are wasted and system performance is severely affected, such as socket, bitmap, and Handle
  • The parent’s destructor is not defined as virtual – when the parent pointer points to a child’s object, the child’s memory will not be freed if the parent’s destructor is not virtual, so memory leaks

Memory leaks are handled in c++ :

Use ValGrind, mTrace to detect memory leaks

Avoid memory leaks:

1. Proactive. Such as intelligent Pointers. 2. Check the wrong type after the fact. Such as leak detection tools.

Smart Pointers

Using smart Pointers, the smart pointer will automatically delete the allocated memory, which is similar to ordinary Pointers, but does not need to manually release the pointer, smart Pointers own memory release, do not worry about memory leaks

Smart Pointers include:

  • auto_ptr
  • unique_ptr
  • shared_ptr
  • weak_ptr

Auto_ptr c++11 has been deprecated

unique_ptr

Exclusive smart Pointers, there can be only one object ownership, the exclusive pointer is own manages memory, stack pointer exists in space, open up the heap space exists inside, the heap space here is binding and smart pointer, smart Pointers as function be destroyed before the end of the smart Pointers will go first to the heap memory inside were destroyed

involving

  • Move function – You can use the move function to transfer ownership. After ownership is transferred, the original pointer is not accessible

  • The reset function – you can use the reset function to reset ownership, freeing the previous ownership of the object and creating a new ownership object

  • Make_unique — Quickly create an object with a unique_ptr smart pointer like auto myptr = make_unique ();

Use unique_ptr if you want only one smart pointer to manage resources

#include <iostream>
#include <string>
#include <memory>

using namespace std;

struct person
{
	~person()
	{
		cout<<"~person"<<endl;
	}
	string str;
};

unique_ptr<person> test(a)
{
	return unique_ptr<person> (new person);
}

int main(a)
{
	//unique_ptr is ownership 
	unique_ptr<person> p = test(a); p->str ="hello world";
	
	unique_ptr<person> p2 = move(p);  // You can use the move function to transfer ownership. After ownership is transferred, the original pointer is not accessible
	if(! p) { cout<<"p == null" <<endl;
	}

	if(p2)
	{
		cout<<"p2 have ownership"<<endl;
		cout<<p2->str<<endl;
	}

	p2.reset(new person);// You can use the reset function to reset ownership, which releases the previous ownership of the object and creates a new ownership object
	if(p2->str.empty())
	{
		cout<<"str is null"<<endl;
	}
 
     return 0;
 }
Copy the code

shared_ptr

Shared_ptr uses reference counting (use_count). Each copy of shared_ptr points to the same block of memory, which is freed when the last shared_ptr is destructed

  • Shared_ptr is the way to count references. Use use_count to view the count

  • Make_shared creates shared_ptr quickly

When using a function to return its own shareD_ptr, you need to inherit enable_shareD_from_this class and use shared_from_this to return

Matters needing attention:

  • Do not use this pointer as a return value

  • Avoid circular references

  • Instead of creating a shared_ptr function argument, define and initialize it before calling the function

  • Do not initialize multiple shareD_ptr with a single raw pointer

If you want multiple Pointers to manage the same resource, use shared_ptr

#include <iostream>
#include <string>
#include <memory>

using namespace std;

struct person
	:enable_shared_from_this<person>{
	string str;
	void show(a)
	{
		cout<<str<<endl;
	}
	~person()
	{
		cout<<"~person"<<endl;
	}
	shared_ptr<person> getshared(a)
	{
		return shared_from_this();
	}
};

int main(a)
{
	#if 0
	shared_ptr<person> ptr(new person);
	cout<< ptr.use_count()<<endl;
	
	shared_ptr<person> ptr2 = ptr;
	cout<< ptr.use_count()<<endl;

	shared_ptr<person> a = make_shared<person>();
	cout<< a.use_count()<<endl;
	a = ptr2;
	cout<< ptr.use_count()<<endl;


	shared_ptr<person> mm = a->getshared(a);#endif

	shared_ptr<person> ptr;
	{
		shared_ptr<person> ptr2(new person);
		ptr2->str = "hello";
		
		ptr = ptr2->getshared(a); cout<< ptr.use_count()<<endl;
	}
	ptr->show(a);return 0;
}
Copy the code

weak_ptr

A smart pointer to a weak reference

Is used to monitor shared_Ptr, does not use counter increments 1, does not use counter decrement 1, mainly to monitor the shared_PTR lifecycle, more like a shared_Ptr helper. Weak_ptr can also be used to return the this pointer and solve the problem of circular references.

Shared_ptr will have the problem of circular reference. The solution is to replace shared_ptr with Weak_ptr in the class

struct ListNode
{
	std::shared_ptr<ListNode> _next;//std::weak_ptr
      
        _next; You can solve it
      
	std::shared_ptr<ListNode>  _prev;//std::weak_ptr
      
        _pre; You can solve it
      
	
	~ListNode()
	{
		cout << "~ListNode()"<< endl; }};void test_shared_ptr_cycleRef(a)
{
	std::shared_ptr<ListNode> cur(new ListNode);
	std::shared_ptr<ListNode> next(new ListNode);
 
	cur->_next = next;
	next->_prev = cur;
 
}
int main(a)
{
	test_shared_ptr_cycleRef(a);system("pause");
	return 0;
}
Copy the code

Take the code example above

void shared_ptr_cycleRef(a){
    std::shared_ptr<LISTNODE> cur LISTNODE;
    std::shared_ptr<LISTNODE> next LISTNODE;

     cur->_next = next;
     next->_pre = cur;
}
Copy the code

Cur and Next have circular references, and their reference counts are both 2

Once out of scope, cur and Next are destroyed and the reference count is reduced by one

So to release cur, you need to release _pre for Next, and to release next, you need to release _next for cur

Memory leak detection tool

Valgrind Memory detection tool

Valgrind’s official website is valgrind.org

Valgrind is designed to be non-invasive and works directly on executable files, so there is no need to recompile, connect, and modify your program before checking. It’s easy to check a program

Command: valgrind –tool=tool_name program_name

  • Do a memory check:valgrind --tool=memcheck ls -l
  • Check for memory leaks:valgrind --tool=memcheck --leak-check=yes ls -l

Valgrind has the following tools:

memcheck

Memcheck detects memory management problems in programs.

It checks all read/write operations to memory and intercepts all malloc/new/free/ DELETE calls. Therefore, the memCheck tool can detect the following problems:

The Memcheck tool checks for the following errors:

  • Use of uninitialised Memory

  • Reading/writing memory after it has been free

  • Reading/writing off the end of Malloc’d blocks

  • (Reading/ Writing inappropriate Areas on the stack)

  • Memory leaks — Where Pointers to Malloc’s blocks are lost forever

  • Mismatched use of malloc/new/new [] vs free/delete/delete []

  • Overlapping SRC and DST (Overlapping SRC and DST Pointers in memcpy() and related functions)

cachegrind

Cachegrind is a cache profiler.

It simulates executing CPU L1, D1, and L2 caches,

Therefore, it can accurately indicate a cache miss in code.

It prints a summary of the number of cache misses, memory references, and every line of code, function, module, and entire program that occurred when a cache miss occurred.

For more detailed information, it can print out the number of misses for each line of machine code.

On x86 and AMD64, CacheGrind automatically probes the machine’s cache configuration through the CPUID, so in most cases it doesn’t need any more configuration information.

helgrind

Helgrind looks for competing data in a multithreaded program.

Helgrind looks for memory addresses that are accessed by more than one thread, but are not locked consistently. This means that these addresses are not synchronized when accessed across multiple threads, which can cause timing problems that are difficult to find.

The cause of the segment error

  • Using wild Pointers
  • Attempted to modify a string constant

Differences between new and malloc:

When allocating memory

  • New is an operator that can be overridden, and malloc is a library function

  • New allocates memory based on the data structure of the object, and malloc allocates the specified size of memory

  • When new requests memory, the constructor is called; malloc does not

  • New returns a pointer to an object when applying for memory. Malloc returns void * when applying for memory

  • When applying for an array, new[] allocates all memory at once and calls multiple constructors, so delete[] is required to destroy memory and destructor multiple times. Malloc can only sizeof(int)*n

  • If new fails to apply for memory, the BAC_malloc exception is thrown. If malloc fails to apply for memory, NULL is returned

  • Malloc uses realloc to reallocate memory when it runs out of allocated memory. New does not have this mechanism.

  • Memory allocated by new needs to be freed by delete, which calls the destructor, and memory allocated by malloc needs to be freed by free

How Realloc works:

Realloc is in C language, C ++ has abandoned the realLOc function, realLOc function allocates a new memory, will copy the original memory into the new memory, through memmove

Shared memory related apis

  • Shmget creates a shared memory
  • Shmat connects shared memory to the current address space
  • SHMDT separates the shared memory
  • SHMCTL controls shared memory

C++ STL memory optimization

New features in c++11:

Keywords and syntax

  • The auto keyword

The compiler can derive data types from initialization, not function arguments and array type inference

  • The nullptr keyword

A special type of literal that can be converted to any other type

  • Initialization list

Initialize the list of classes

  • Rvalue references

It can realize mobile semantics and perfect forwarding, eliminate unnecessary copy when two objects interact, save storage resources and improve efficiency

The new container

  • Added STL array, tuple, unORDERed_map, unORDERed_set

Smart pointer, memory management

  • Smart Pointers

Shared_ptr and Weak_pTR are added for memory management

multithreading

  • Atomic operation

Used for multi-threaded mutex

other

  • Lambda expressions

You can access context data through a capture list

  • STD ::function STD ::bin D encapsulates executable objects

Prevent double references to header files:

#ifndef

Effect: The same two files will not be included twice.

Advantages:

  • It is supported by the C/C++ language standard and is not limited by the compiler.
  • This is not limited to avoiding double inclusion of the same file, but also two files (or code snippets) with identical contents.

Disadvantages:

  • If the macro names in different header files happen to be the same, you might see the header file exist, but the compiler says it can’t find the declaration.
  • Since the compiler needs to open the header file each time to determine if there is a duplicate definition, #ifndef makes compiling time relatively long when compiling large projects.

#pragma once

Effect: The same physical file is not included twice.

Advantages:

  • Avoid #ifndef problems caused by the same macro name.
  • Because the compiler does not need to open the header file to determine if there are duplicate definitions, it is faster than #ifndef when compiling large projects.

Disadvantages:

  • #pragma once works only for the same file, not for the same two files (or snippets of code)
  • #pragma once is not supported by some older compilers, and some compilers that do support it want to remove it, so it may not be compatible enough.

Inheritance and composition

  • Inheritance is one of the three basic characteristics of object-oriented, inheritance, encapsulation, polymorphism, inheritance is a subclass inherits the characteristics and behavior of the parent class, making a subclass object (instance) have instance fields and methods of the parent class, or subclass from the parent class method, makes the subclass has the same behavior, the parent class inheritance relationship, that is – a “white box” is a * * * * code reuse
  • Combination is to create new and more complex functions by assembling existing objects. Combination reflects the whole and parts, emphasizes the relationship of HAS-A, and is the code reuse of “black box”

Inheritance and combined use scenarios

  • B is logically A’s"A"(a kind of

To inherit, eg from a man

  • Logically, A is B’sPart of(a part of)

Combination (e.g. combination of eyes, ears, mouth, nose -> head)

Inheritance vs. composition

  • In inheritance, the internal details of the parent class are visible to the subclass, whose code is reused in a white box, calling the IS-A relationship, which is determined at compile time
  • In composition, the internal details between objects are not visible, and the code is black-box reuse. The emphasis is on has-A relationships, which are generally determined at run time

Advantages and disadvantages of inheritance and composition

inheritance

Advantages:

  • Support extension, by inheriting the parent class implementation, but will make the system structure more complex
  • Easy to modify reused code

Disadvantages:

  • Code is reused in white boxes, and the implementation details of the parent class are exposed to the subclasses, breaking encapsulation
  • When the implementation code of the parent class changes, it may force the subclass to change as well, making maintenance more difficult.
  • The subclass lacks independence, depends on the parent class, and has high coupling degree
  • Dynamic extension is not supported and parent classes are determined at compile time

combination

Advantages:

  • Code black box reuse, the included object internal implementation details are not visible to the outside, encapsulation is good.
  • Global and local classes are loosely coupled and independent of each other.
  • Support extended
  • Each class focuses on only one task
  • Support for dynamic extension, which allows you to select different types of composite objects based on specific objects at run time (extensibility is better than inheritance)

Disadvantages:

  • To create a global class object, you need to create all local class objects. Many system objects result.

Function pointer benefits and functions:

Benefits: Simplifies the problems of structure and program generality, and is also a way to achieve object-oriented programming

Function:

  • Implement polymorphism in object-oriented programming

  • The callback function

Inline functions and macro definitions

Inline functions are a mechanism introduced by C++ to address some of the drawbacks of using macro definitions.

Why inline functions are introduced

Use it to replace macro definition and eliminate the disadvantages of macro definition.

Macro definitions are implemented using a preprocessor, do some simple character substitution, so the parameter validity can not be detected.

  • Inline has some advantages over macro definitions

  • The inline function code is placed in the symbol table and expanded like a macro when used, which is efficient without the overhead of calling.

  • Inline functions are real functions, so a series of data type checks are performed;

  • As a member function of a class, inline functions can use the protected and private members of the class.

Where inline functions are used

  • Inline functions can be used wherever macro definitions are used;
  • As a class member interface function to read and write private members of a class or protect members;

Why can’t all functions be inline

  • The code in the function body is long, resulting in memory consumption costs;
  • There is a loop in the function body, and the function execution time is more expensive than the function call;
  • Do not write the constructor and destructor of other classes as inline functions.

Inline functions differ from macro definitions

  • Inline functions are expanded at compile time and macros are expanded at precompile time;
  • Inline functions are embedded directly into the object code, and macros are simple text replacements;
  • Inline functions have functions such as type detection and syntax judgment, while macros do not.
  • Inline functions are functions, macros are not;
  • When defining macros, pay attention to writing (parameters should be enclosed), otherwise it is easy to have ambiguity, and inline functions will not have ambiguity;

conclusion

  • Shared memory management, memory leaks, smart Pointers
  • Memory leak detection tool
  • The cause of segment errors in code
  • Memory optimization
  • Other tips

Welcome to like, follow and favorites

Friends, your support and encouragement, I insist on sharing, improve the quality of the power

Ok, that’s it for now, ** next concurrent programming share of GO **

Technology is open, our mentality, should be more open. Embrace change, live in the sun, and strive to move forward.

I am Nezha, welcome to like, see you next time ~