Memory Direct Operation Methods in C and C++ Language Development

In C and C++ language development, pointers and memory have always been the focus of learning. Because C language is a kind of low-level low-level language, it provides a large amount of direct memory manipulation. This aspect maximizes the flexibility of the program and also lays a lot of hidden trouble for bugs.

Therefore, we must have a clear understanding of memory anyway.

First, the distribution of the inside

The 32-bit operating system supports continuous access to 4GB of memory, but usually divides the memory into two 2GB spaces. Each process can use up to 2GB of private memory (0x00000000-0x7FFFFFFF) at runtime. That is, the following large array is supported theoretically:

Char szBuffer[2*1024*1024*1024];

Of course, since the program has code segments, temporary variable segments, dynamic memory requests, etc., it is practically impossible to use such large arrays.

As for the high-end 2GB memory address (0x80000000 - 0xFFFFFFFF), the operating system is generally reserved internally for use by the operating system kernel code. On Windows and Linux platforms, some dynamic link libraries (Windows dll, Linux so) and ocx controls, etc., are generally running at a high 2GB memory space because they are inter-process services.

As you can see, each process can see its own 2GB of memory and 2GB of system memory, but it is impossible for different processes to see each other. Of course, the operating system does a lot of work in the bottom layer, such as virtual memory swapping on disk (see under the heading), dynamic mapping of different memory blocks, and so on.

Second, virtual memory

The basic idea of ​​virtual memory is to use cheap but slow disks to expand fast but expensive memory. At a certain moment, the contents of the virtual memory section that the program actually needs to use are loaded into physical memory. When the data in physical memory is not used for a period of time, they may be transferred to the hard disk. The saved physical memory space is used to load other data that needs to be used.

During the execution of the process, the operating system is responsible for the specific details so that each process assumes that it has exclusive access to the entire address space. This illusion is achieved through "virtual memory." All processes share the physical memory of the machine and use the disk to save the data when the memory is used up. As the process runs, data moves back and forth between disk and memory. The memory management hardware is responsible for translating the virtual address into a physical address, and letting a process always run in the real memory of the system. The application programmer only sees the virtual address, and does not know that its own process is switching between disk and memory.

In terms of potential possibilities, all memory associated with the process will be used by the system. If the process may not be running right away (maybe it has a low priority or it may be sleeping), the operating system may temporarily Retrieves all the physical memory resources allocated to it and backs up all relevant information about the process to disk.

Processes can only operate on pages that are in physical memory. When a process references a page that is not in physical memory, MMU generates a page fault. Memory responds to this matter and determines if the citation is valid. If invalid, the kernel sends a “segmentation violation” signal to the process. The kernel fetches the page from the disk and swaps it into memory. Once the page enters memory, the process is unlocked and can be re-run — the process itself. I don't know if it used to wait for a page because of a page swap event.

Third, the use of memory

For programmers, the most important thing is to understand the meaning of private memory space between different processes. C and C++ compilers divide private memory into three blocks: base stacks, floating stacks, and heaps. As shown below:

(1) Base stack: Also called static storage area, this is the memory that the compiler has fixed during compiling, such as program code segment, static variables, global variables, const constants, etc.

(2) Floating stack: Many books are called "stacks". That is, the program starts to run. With the execution of functions and objects, the internal variables of the function and the internal member variables of the object start to occupy memory dynamically. The floating stack generally has a life cycle. The end of the function or the destruction of the object, the corresponding floating stack space is removed, this part of the content is always changing, memory usage is not fixed, so called the floating stack.

(3) Heap: Both C and C++ languages ​​support dynamic memory request, that is, the program can freely apply for memory during runtime. This part of memory is applied in the heap space. The heap is located at the top of the 2GB, allocated from top to bottom, which is to avoid mixing with the floating stack and is not well managed. We use malloc and new to apply memory from the heap space. New supports more objects than malloc and can automatically call constructors. In addition, new creates an object whose member variables are in the heap.

Let's take a look at an example:

Constintn = 100;

voidFunc(void)

{

Charch = 0;

Char* pBuff = (char*)malloc(10);

//...

}

If this function is run, where n is a global static variable, it is located in the base stack, ch and pBuff are internal functions, ch is on the floating stack, and the memory area allocated by malloc pointed to by pBuff is on the stack.

In memory understanding, the most famous example is the parameter transfer at thread startup.

Function to start a thread, many times need to pass parameters to the thread, but the thread is asynchronously started, that is likely to start the function has exited, and the thread function has not yet officially started running, therefore, must not use the internal variables of the start function The thread passes parameters. The reason is very simple. The internal variables of the function are on the floating stack, but when the function exits, the floating stack is automatically removed and the memory space has been released. When the thread starts, querying the variable according to the given parameter pointer actually reads an invalid memory area and the program will crash.

then what should we do? We should directly use the malloc function to allocate a memory area to the parameters that we need to pass, pass the pointer to the thread, use it after the thread receives it, and release it when the thread exits.

Let's look at an example:

//This structure is the parameter table

typedefstruct_CListen_ListenAcceptTask_Param_

{

Linux_Win_SOCKET m_nSocket;

//other parameters...

}SCListenAcceptTaskParam;

/ / Customary writing, set the structure immediately after the declaration of the size of the structure, to facilitate the follow-up malloc

constULONG SCListenAcceptTaskParamSize = sizeof(SCListenAcceptTaskParam);

//Receive the connection request here, apply for the parameter area, and bring the key information into the parameter area to help the subsequent thread work.

boolCListen::ListenTaskCallback(void* pCallParam,int& nStatus)

{

//normal function logic...

// Assume that s is the accept socket, need to pass in the subsequent thread work

// Prepare a parameter area here and apply from far

SCListenAcceptTaskParam*pParam = (SCListenAcceptTaskParam*)malloc(SCListenAcceptTaskParamSize);

// Assign to the parameter area

pParam->m_nSocket = s;

//Start the thread here and pass pParam to the thread...

//normal function logic...

}

// This is a thread function that handles sockets accepted above.

boolCListen::ListenAcceptTask(void* pCallParam,int& nStatus)

{

// The first sentence is to force pointer type conversion and get the incoming parameter area

SCListenAcceptTaskParam*pParam= (SCListenAcceptTaskParam*)pCallParam;

//normal function logic...

//The work that must be done before leaving to ensure that resources are not leaked

Close(pParam->m_nSocket);//close the socket

Free(pCallParam);// free incoming parameter area

//... ...

}

Fourth, memory bug

Irregular abuse of memory and pointers can cause a large number of bugs. Programmers should maintain a high degree of sensitivity and alertness to the use of memory and use memory resources sparingly.

The most common bugs when using memory are:

(1) Bad pointer value error: It is used to refer to memory before the pointer is assigned, or to send a bad pointer to the library function. The third reason that may cause the bad pointer is to release the pointer and then access its contents. You can modify the free statement and set it to null after the pointer is released.

Free(p); p = NULL;

In this way, if the pointer continues to be used after the pointer is released, at least the program can dump the information before it terminates.

(2) Overwrite errors: writing data across array boundaries, writing data outside of dynamically allocated memory, or overwriting some heap management data structures (writing data in the area before dynamically allocating memory is easy This happens)

p = malloc(256); p[-1] = 0; p[256] = 0;

(3) Error caused by pointer release: Release the same memory block twice, or release a memory that has not been allocated using malloc, or release memory that is still in use, or release an invalid pointer. An extremely common memory-related error is to iterate over a list in a loop like for (p=start;p=p->next) and use the free(p) statement in the body of the loop. In this way, on the next iteration of the loop, the program will dereference the already released pointer, resulting in unpredictable results.

We can iterate like this:

Structnode *p, *tart, *temp;

For(p = start;p;p = temp)

{

Temp = p->next;

Free(p);

}

Summary: This knowledge is summed up by my recent reading. There may be many subjective individuals. Welcome to take a picture...

LED DJ Console Display

LED DJ Console Display is a kind of led electronic display screen designed and made according to the customer's specific requirements. DJ Table LED Display Stage can be applied in many fields due to its flexibility of control and combination. It is a bar mark, which is the most distinctive stage facade.

It has an impact on the stage, starts from this moment. It can be widely used in bars, KTV, stage performance and other places.

Characteristics

1. Exquisite effect, smooth transition

2. Assemble and disassemble design, quick and convenient maintenance

3. Innovative unique creation, bar vision 3D design concept

LED DJ Console Display, Fantasy LED DJ Console Display, Video LED DJ Console Display, LED Honeycomb DJ Console Display

Shenzhen Priva Tech Co., Ltd. , https://www.privaled.com

This entry was posted in on