头图

Do not miss the back-end [pure dry goods] interview knowledge points finishing II

c++ memory management

Last time I shared the interview knowledge points I organized, today we will continue to share the interview knowledge points II

linux kernel kernel space, memory management, process management equipment, drive virtual file system (vfs)The kernel space is protected, users cannot read or write to the kernel space, otherwise a segmentation fault will occur
environment variable (env) PATH
command line parameters char *agrv[]
stack area ⬇️ Function's return address, return value, parameters, local variables
shared library (mapping area) ⬇️ Call dynamic library, or mmap function for file mapping
heap area ⬆️ Use new/malloc to apply for the memory, and also need to apply delete/free to release the chain storage structure
.bss area Uninitialized global variables and static variables, as well as global variables and static variables initialized to 0, have been allocated space at compile time
area Initialized global variables and static variables have been allocated space at compile time
.text1. Read-only storage area-constants, const global variables 2. Text area-program code, machine code
0-4k protected area
#include<stdio.h>
 
int a;    //未初始化全局区 .bss
int b=1;    //已初始化全局区  .data
static int c=2;    //已初始化全局区  .data
const int d=3;    //只读数据段,也叫文字常量区 ro.data, d的值不能被修改
int main(void)
{
    int e=4;    //栈区
    static int f=5;    //已初始化全局区
    const int g=6;    //栈区,不能通过变量名修改其值,但可通过其地址修改其值
    int *p=malloc(sizeof(int))    //指针变量p在栈区,但其所指向的4字节空间在堆区
    char *str="abcd";    //字符串“abcd”存在文字常量区,指针变量str在栈区,存的是“abcd”的起始地址
    return 0;
}

Memory leak and classification

img

Memory leaks are due to negligence or errors causing the program to fail to release memory that is no longer in use. Memory leak does not mean the disappearance of the memory from the physical address, but after the application program allocates a certain segment of memory, it loses control of that segment of memory, which causes a waste of memory.

  • The general situation is that after new/malloc, the memory is not released in time by delete/free, and it is judged as a memory leak
  • You can use valgrind to detect memory leaks in Linux

memory leak classification:

  • Heap memory leak --- no delete/free drop after new/malloc
  • Leakage of system resources --- The resources allocated by the system are not released with the specified function, which leads to a waste of system resources and seriously affects system performance, such as socket, bitmap, handle
  • The destructor of the parent class is not defined as a virtual function --- when the parent class pointer points to the child class object, when the memory is released, if the parent class’s destructor function is not virtual, the memory of the child class will not be released , So there will be a memory leak

How to deal with memory leaks in c++:

Use valgrind , mtrace to detect memory leaks

Avoid memory leaks:

1. Precautionary type. Such as smart pointers. 2. Check the error afterwards. Such as leak detection tools.

Smart pointer

Using a smart pointer, the smart pointer will automatically delete the allocated memory. It is similar to a normal pointer, except that there is no need to manually release the pointer. The smart pointer manages the memory release by itself, so there is no need to worry about memory leaks.

Smart pointers are:

  • auto_ptr
  • unique_ptr
  • shared_ptr
  • weak_ptr

Among them, auto_ptr c++11 has been deprecated

unique_ptr

An exclusive smart pointer can only have ownership of one object. The exclusive pointer manages the memory by itself. The pointer exists in the stack space, and the opened memory is in the heap space. The heap space here is bound to the smart pointer, and the smart pointer follows Before the function is destroyed, the smart pointer will first destroy the memory in the heap

Which involves

  • move function - You can use the move function to transfer ownership. After ownership is transferred, the original pointer has no right to access
  • reset function - You can use the reset function to reset ownership, which will release the ownership of the previous object and recreate an ownership object
  • make_unique - quickly create a unique_ptr smart pointer object such as auto myptr = make_unique<person>();

If you want only one smart pointer to manage resources, use unique_ptr

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

using namespace std;

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

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

int main()
{
    //unique_ptr is ownership 
    unique_ptr<person> p = test();
    p->str = "hello world";
    
    unique_ptr<person> p2 = move(p);  //可以使用move函数来转移所有权,转移所有权后,原来的指针就无权访问
    if(!p)
    {
        cout<<"p == null" <<endl;
    }

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

    p2.reset(new person);//可以用reset函数来重置所有权,会把之前的对象所有权释放掉,重新创建一个所有权对象
    if(p2->str.empty())
    {
        cout<<"str is null"<<endl;
    }
 
     return 0;
 }

shared_ptr

Shared smart pointer, shared_ptr uses reference counting (use_count method), each shared_ptr points to the same block of memory, and the memory will be released when the last shared_ptr is destroyed

  • shared_ptr is a reference counting method, use use_count to view the count
  • make_shared quickly create shared_ptr

When using a function to return your own shared_ptr , you need to inherit the enable_shared_from_this class and use the shared_from_this function to return

Precautions:

  • Do not use this pointer as a return value
  • To avoid circular references
  • Do not create shared_ptr with function arguments, define and initialize it before calling the function
  • Don't initialize multiple shared_ptr with one raw pointer

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()
    {
        cout<<str<<endl;
    }
    ~person()
    {
        cout<<"~person"<<endl;
    }
    shared_ptr<person> getshared()
    {
        return shared_from_this();
    }
};

int main()
{
    #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();
    
    #endif

    shared_ptr<person> ptr;
    {
        shared_ptr<person> ptr2(new person);
        ptr2->str = "hello";
        
        ptr = ptr2->getshared();    
        cout<< ptr.use_count()<<endl;
    }
    ptr->show();

    return 0;
}

weak_ptr

Weakly referenced smart pointers

It is used to monitor shared_ptr. It does not use the counter to increase by 1, and it does not use the counter to decrease by 1, mainly to monitor the life cycle of shared_ptr, and is more like an assistant to shared_ptr. Weak_ptr can also be used to return this pointer and solve the problem of circular references.

shared_ptr will have a circular reference problem, the solution is to replace the shared_ptr in the class with weak_ptr

struct ListNode
{
    std::shared_ptr<ListNode> _next;//std::weak_ptr<ListNode> _next; 就可以解决
    std::shared_ptr<ListNode>  _prev;//std::weak_ptr<ListNode> _pre; 就可以解决
    
    ~ListNode()
    {
        cout << "~ListNode()" << endl;
    }
};
void test_shared_ptr_cycleRef()
{
    std::shared_ptr<ListNode> cur(new ListNode);
    std::shared_ptr<ListNode> next(new ListNode);
 
    cur->_next = next;
    next->_prev = cur;
 
}
int main()
{
    test_shared_ptr_cycleRef();
    system("pause");
    return 0;
}

For example, the above code case

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

     cur->_next = next;
     next->_pre = cur;
}

Cur and next have circular references, and their reference counts both become 2

out of scope, cur and next are destroyed, and the reference count is decremented by 1

Therefore, to release cur, you need to release the _pre of next, and to release next, you need to release the _next of cur

Memory leak detection tool

valgrind memory detection tool

The official website of valgrind is: http://valgrind.org

Valgrind is designed to be non-intrusive, it works directly on executable files, so there is no need to recompile, link and modify your program before checking. To check a program is simple

The command is as follows: valgrind --tool=tool_name program_name

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

has the following tools :

memcheck

memcheck detects problems with memory management in the program.

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

The Memcheck tool mainly checks the following program errors:

  • Use of uninitialised memory
  • Use memory that has been released (Reading/writing memory after it has been free'd)
  • Use more memory space allocated by malloc (Reading/writing off the end of malloc'd blocks)
  • Illegal access to the stack (Reading/writing inappropriate areas on the stack)
  • The requested space has been released, that is, memory leaks (Memory leaks – where pointers to malloc'd blocks are lost forever)
  • Malloc/free/new/delete application and release of memory matching (Mismatched use of malloc/new/new [] vs free/delete/delete [])
  • Overlapping src and dst pointers in memcpy() and related functions

cachegrind

cachegrind is a cache parser.

It simulates the implementation of L1, D1 and L2 cache in the CPU,

Therefore, it can accurately point out cache misses in the code.

It can print out the number of cache misses, memory references and a summary of each line of code where cache misses occurred, each function, each module and the entire program.

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

On x86 and amd64, cachegrind automatically detects the cache configuration of the machine through the CPUID, so in most cases it does not need more configuration information.

helgrind

Helgrind finds competing data in multithreaded programs.

Helgrind looks for memory addresses. Those memory addresses that are accessed by more than one thread, but do not use a consistent lock will be found out. This means that these addresses are not synchronized when accessed between multiple threads, which is likely to cause timing problems that are difficult to find.

The cause of the segfault

  • Use wild pointer
  • Attempt to modify a string constant

The difference between new and malloc:

When applying for memory

  • new is an operator and can be overloaded, malloc is a library function
  • When new applies for memory, it allocates memory according to the data structure of the object, and malloc allocates the specified memory size
  • When new applies for memory, it will call the constructor, malloc will not
  • When new applies for memory, it returns the pointer of the object. When malloc applies for memory, it returns (void *), so it needs to be forced.
  • When applying for an array, new[] will allocate all memory at once and call multiple constructors. Therefore, delete[] is needed to destroy the memory and call multiple destructors, while malloc can only be sizeof(int)*n
  • New memory application fails, bac_malloc exception will be thrown, malloc application failure returns NULL
  • malloc will use realloc to allocate memory again when the allocated memory is not enough, new does not have such a mechanism.
  • The memory allocated by new needs to be released by delete, and delete will call the destructor. The memory allocated by malloc needs to be released by the free function.

The principle of

Realloc appears in the C language. C++ has abandoned the realloc function. When the realloc function allocates a piece of new memory, it will copy the memory in the original memory to the new memory by means of memmove.

Shared memory related API

  • shmget new shared memory
  • shmat connects shared memory to the current address space
  • shmdt separate shared memory
  • shmctl controls shared memory

c++ STL memory optimization

c++11 new features:

Keywords and syntax

  • auto keyword

The compiler can deduce the data type according to the initialization, and cannot be used for function parameter passing and array type derivation

  • nullptr keyword

A special type of literal, which can be converted to any other type

  • Initialization list

List of initialized classes

  • Rvalue reference

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

New container

  • Added STL array, tuple, unordered_map, unordered_set

smart pointer, memory management

  • Smart pointer

Added shared_ptr and weak_ptr for memory management

multi-threaded

  • atomic atomic operation

For multi-threaded mutual exclusion

other

  • lamda expression

The data of the context can be accessed through the capture list

  • std::function std::bin d package executable object

Prevent duplicate references in header files:

#ifndef

Role: The same two files will not be included repeatedly.

Advantages:

  • Supported by the C/C++ language standard and not restricted by the compiler.
  • It is not only limited to avoiding the repeated inclusion of the same file, but also avoiding the repeated inclusion of two files (or code fragments) with exactly the same content.

Disadvantages:

  • If the macro names in different header files happen to be the same, it may cause you to see that the header file clearly exists, but the compiler says it cannot find the declaration.
  • Because the compiler needs to open the header file every time to determine whether there are duplicate definitions, when compiling large projects, #ifndef will make the compilation time relatively long.

pragma once

Role: The same physical file will not be included repeatedly.

Advantages:

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

Disadvantages:

  • \#pragma once is only valid for the same file, and invalid for the same two files (or code fragments)
  • \#pragma once is not supported by some older compilers, and some supported compilers plan to remove it, so its compatibility may not be good enough.

Inheritance and combination

  • Inheritance is one of the three basic characteristics of object-oriented (inheritance, encapsulation, polymorphism). Inheritance is that the subclass inherits the characteristics and behaviors of the parent class, so that the subclass object (instance) has the instance domain and method of the parent class, or the subclass Inheriting methods from the parent class makes the child class have the same behavior as the parent class. Inheritance emphasizes the is-a relationship, which is box style' code reuse
  • Combination is to combine existing objects to produce new and more complex functions. Combination reflects the whole and part, and emphasizes the has-a relationship, which is box' code reuse

Inheritance and combination use scenario

  • Logically, B is the "kind" of A ( a kind of )

Inheritance (as a man inherits a human being)

  • A is B is logically "part" ( A Part of )

Combination (such as combining eyes, ears, nose and mouth -> head)

Difference between inheritance and combination

  • In inheritance, the internal details of the parent class are visible to the child class. The code belongs to the white box multiplexing, and is-a . The relationship is determined at compile time.
  • In the combination, the internal details between the objects are not visible, and the code belongs to the black box multiplexing. The emphasis is on the has-a relationship, which is generally determined at runtime

Inheritance and combination advantages and disadvantages

inherits

advantages:

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

Disadvantages:

  • White box reuse of code, the implementation details of the parent class are exposed to the child class, destroying the encapsulation
  • When the implementation code of the parent class is modified, the subclass may also have to be modified, which increases the difficulty of maintenance.
  • The sub-category lacks independence, depends on the parent category, and has a high degree of coupling
  • Does not support dynamic expansion, the parent class is determined at compile time

combination

advantages:

  • The code is reused in a black box, the internal implementation details of the included objects are invisible to the outside, and the encapsulation is good.
  • The overall class and the local class are loosely coupled and independent of each other.
  • Support extension
  • Each class focuses on only one task
  • Support dynamic expansion, different types of combined objects can be selected according to specific objects at runtime (extensibility is better than inheritance)

Disadvantages:

  • When creating an overall class object, all local class objects need to be created. Lead to a lot of system objects.

Function pointer benefits and functions:

Benefits: simplifying the structure and program versatility is also a way to realize object-oriented programming

role:

  • Implement polymorphism in object-oriented programming
  • Callback

inline function and macro definition

inline function is a mechanism introduced by C++ to solve some shortcomings of using macro definitions.

Why introduce inline functions (the role of inline functions)

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

macro definition uses a preprocessor to implement , and does some simple character substitutions, so the validity of the parameters cannot be tested.

  • What are the advantages of inline over macro definitions
  • The inline function code is placed in the symbol table and expanded like a macro when used, and it is very efficient without the overhead of calling;
  • The inline function is a real function, so a series of data type checks are required;
  • Inline function as a member function of the class, you can use the protected members and private members of the class;

inline function is used

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

Why can't all functions be written as inline functions

  • The code in the function body is relatively long, which will cause the cost of memory consumption;
  • There are loops in the function body, and the execution time of the function is more expensive than the function call;
  • In addition, the structure and destructor of the class should not be written as inline functions.

The difference between inline function and macro definition

  • Inline functions are expanded at compile time, and macros are expanded at precompilation;
  • Inline functions are directly embedded in the target code, and macros are simply text replacements;
  • Inline functions have functions such as type detection and grammar judgment, but macros do not;
  • Inline functions are functions, but macros are not;
  • Pay attention to writing when defining macros (parameters should be enclosed), otherwise ambiguity is likely to occur, and inline functions will not cause ambiguity;

to sum up

  • Shared memory management, memory leaks, smart pointers
  • Memory leak detection tool
  • The reason for the segfault in the code
  • Memory optimization
  • Other small knowledge points

Welcome to like, follow, favorite

Friends, your support and encouragement are my motivation to keep sharing and improve quality

Well, that’s it for this time, Next time GO concurrent programming sharing

Technology is open, and our mindset should be more open. Embrace the change, live toward the sun, and work hard to move forward.

I am little magic boy , welcome to like and follow the collection, see you next time~


阿兵云原生
192 声望37 粉丝