I. Classification of Memory Errors
A. Memory Access Error
An error occurs when the memory is read or written. It may be a memory unit that has not been initialized, or a memory unit that has been read or written incorrectly.
B. memory usage Error
This error occurs when the memory is not correctly released after the dynamic request.
Ii. Memory analysis (typical C ++ Memory Model)
BSS segment: BSS segment (BSS segment) is usually a memory area used to store uninitialized global variables in the program. BSS is short for block started by symbol. BSS segments belong to static memory allocation.
Data Segment: a data segment is usually a memory area used to store initialized global variables in the program. The data segment belongs to the static memory allocation. (In fact, I don't quite understand why we manage initialized and uninitialized segments since they all store global variables)
Code segment: A code segment (code segment/Text Segment) is usually a memory area used to store Program Execution Code. The size of this area is determined before the program runs, and the memory area is usually read-only. Some architectures also allow code segments to be writable, that is, programs can be modified. In the code segment, it may also contain some read-only constant variables, such as string constants.
Heap: a heap is used to store the memory segments dynamically allocated during a process. Its size is not fixed and can be dynamically expanded or reduced. When a process calls a function such as malloc to allocate memory, the newly allocated memory is dynamically added to the heap (the heap is expanded). When a function such as free is used to release the memory, released memory is removed from the heap (the heap is reduced)
STACK: A stack, also known as a stack, is a local variable temporarily created by the user to store the program. That is to say, the variable defined in the callback arc "{}" (but does not include static declared variables, static means to store variables in data segments ). In addition, when a function is called, its parameters will also be pushed into the process stack that initiates the call. After the call is completed, the return values of the function will also be stored in the stack. Because of the stack's first-in-first-out feature, the stack is particularly convenient for storage/ Resume the call site. In this sense, we can regard the stack as a memory zone for storing and exchanging temporary data.
C ++ is different from C # and Java in that it can dynamically manage the memory, but it cannot have both of them, the cost of flexibility is that programmers need to spend more energy to ensure that the Code does not encounter memory errors.
Iii. Common memory access errors and memory usage errors
Specifically, memory access errors include the following: uninitialized memory units, array access errors, invalid memory units (0x000000, 0x000005, etc.), and invalid write memory.
Memory usage errors include: 1. The memory is not released after the request, which can be avoided by pairing new and delete. 2. Release a piece of memory and then release it again.
Iv. Example
- # Include <iostream>
- Using namespace STD;
- Int main ()
- {
- Char * str1 = "four ";
- Char * str2 = new char [4]; // not enough space
- Char * str3 = str2;
- Cout <str2 <Endl; // UMR
- Strcpy (str2, str1); // ABW
- Cout <str2 <Endl; // ABR
- Delete str2;
- Str2 [0] + = 2; // FMR and fmw
- Delete str3; // FFM
- }
UMR: uninitialized memery read. Read Memory not initialized
ABW: array bound write. array out-of-bounds write
FMR/W: freed memery read/write. read/write memory released
FFM: Free freed memery. Release released memory
From the above program, we can see that when 5th rows are allocated with memory, the space occupied by the string Terminator "/0" is ignored, resulting in out-of-bounds write of the array of 8th rows (Array Bounds Write) and Array bounds read; in row 9th, printing str2 that has not been assigned a value will generate an uninitialized memory error (uninitialized memory read ); using released variables in Row 3 will lead to errors in releasing memory read and write (freed memory read and freed memory write). Finally, because str3 and str2 refer to the same memory, row 3 releases the space that has been released again (free freed memory ).
This program contains many errors and can be compiled and connected and run on many platforms. However, these errors are like time bombs that will be triggered under special configurations, resulting in unforeseen errors. This is one of the main reasons why memory errors are hard to be found.
Memory leakage Definition
Generally, memory leakage refers to heap memory leakage. Heap memory refers to the memory allocated by the program from the heap, which is of any size (the size of the memory block can be determined during the running period). The released memory must be displayed after use. Applications generally use functions such as malloc, realloc, and new to allocate a block of memory from the heap. after use, the program must call free or delete to release the block. Otherwise, this memory cannot be used again, so we can say this memory is leaked. The following applet demonstrates heap memory leakage:
- Void myfunction (INT nsize)
- {
- Char * P = new char [nsize];
- If (! Getstringfrom (p, nsize )){
- MessageBox ("error ");
- Return;
- }
- ... // Using the string pointed by P;
- Delete P;
- }
Example 1
When the getstringfrom () function returns zero, the memory pointed to by the pointer P will not be released. This is a common case of Memory leakage. The program allocates memory at the entrance and releases the memory at the exit. However, the C function can exit from anywhere. Therefore, a memory leak may occur if a certain exit does not release the memory that should be released.
Broadly speaking, memory leaks include not only heap memory leaks, but also system resource leaks, such as core handle, GDI object, socket, and interface, basically, these objects allocated by the operating system also consume memory. If these objects are leaked, memory leakage will eventually occur. In addition, some objects consume core-state memory, which causes instability of the entire operating system when such objects are seriously leaked. Therefore, the system resource leakage is more serious than the heap memory leakage.
The leakage of GDI object is a common resource leakage:
- Void cmyview: onpaint (CDC * PDC)
- {
- Cbitmap BMP;
- Cbitmap * poldbmp;
- BMP. loadbitmap (idb_mybmp );
- Poldbmp = PDC-> SelectObject (& BMP );
- ...
- If (something ()){
- Return;
- }
- PDC-> SelectObject (poldbmp );
- Return;
- }
Example 2
When something () returns a non-zero value, the program does not select poldbmp back to PDC before exiting. This will cause the hbitmap object pointed to by poldbmp to leak. If this program runs for a long time, the entire system may be blurred. This problem is easily exposed in Win9x, because the GDI Heap of Win9x is much smaller than that of Win2k or NT.
Memory leakage occurs in the following ways:
Memory leakage can be classified as follows:
1. Frequent Memory leakage. Code with Memory leakage will be executed multiple times, resulting in a memory leak each time it is executed. For example, if the something () function returns true all the time, the hbitmap object pointed to by poldbmp always leaks.
2. Occasional Memory leakage. Memory leakage occurs only in certain environments or operations. For example, if the something () function returns true only in a specific environment, the hbitmap object pointed to by poldbmp does not always leak. The frequency and frequency are relative. For a specific environment, unexpected events may become frequent. Therefore, the test environment and test method are crucial for detecting memory leaks.
3. One-time memory leakage. The code with Memory leakage is executed only once, or due to algorithm defects, there will always be only one piece of Memory leakage. For example, the class constructor allocates the memory, but the memory is not released in the destructor. However, because the class is a Singleton, the memory leakage only occurs once. Another example:
- Char * g_lpszfilename = NULL;
- Void setfilename (const char * lpcszfilename)
- {
- If (g_lpszfilename ){
- Free (g_lpszfilename );
- }
- G_lpszfilename = strdup (lpcszfilename );
- }
Example 3
If the program does not release the string pointed to by g_lpszfilename at the end, even if setfilename () is called multiple times, there will always be one piece of memory, and only one piece of memory will leak.
4. Implicit Memory leakage. The program continuously allocates memory during the running process, but it does not release the memory until it ends. Strictly speaking, there is no memory leakage because the program releases all requested memory. However, if a server program needs to run for several days, weeks, or even months, failing to release the memory in time may eventually exhaust all the system memory. Therefore, we call this type of Memory leakage an implicit memory leak. For example:
- Class connection
- {
- Public:
- Connection (socket S );
- ~ Connection ();
- ...
- PRIVATE:
- Socket _ socket;
- ...
- };
- Class connectionmanager
- {
- Public:
- Connectionmanager (){}
- ~ Connectionmanager (){
- List: iterator it;
- For (IT = _ connlist. Begin (); it! = _ Connlist. End (); ++ it ){
- Delete (* it );
- }
- _ Connlist. Clear ();
- }
- Void onclientconnected (socket s ){
- Connection * P = new connection (s );
- _ Connlist. push_back (P );
- }
- Void onclientdisconnected (connection * pconn ){
- _ Connlist. Remove (pconn );
- Delete pconn;
- }
- PRIVATE:
- LIST _ connlist;
- };
Example 4
If the server does not call the onclientdisconnected () function after the client is disconnected from the server, the connection object of the connection will not be deleted in time (when the server program exits, all connection objects will be deleted in the onmanager destructor ). Implicit Memory leakage occurs when connections are established and disconnected constantly.