(Study Notes - Memory Management) Memory Segmentation, Paging, Management and Layout

memory segmentation

A program is composed of several logical segments, such as code segments, data segments, stack segments, and heap segments. Different segments have different attributes, so these segments are separated in the form of segments .

Under the segmentation mechanism, how are virtual addresses and physical addresses mapped?

 The virtual address under the segmentation mechanism consists of two parts, the segment selection factor and the offset within the segment

  •  Segment selection factor : stored in the segment register. The most important segment selection factor is the segment number , which is used as the index of the segment table. The segment table stores the segment's base address, segment boundaries, and privilege levels .
  • The intra-segment offset  in the virtual address should be between 0 and the segment limit. If the intra-segment offset is legal, add the segment base address to the segment offset to obtain the physical memory address.

The above figure shows the mapping relationship between the virtual address and the physical address through the segment table. The segmentation mechanism will divide the virtual address of the program into 4 segments. Each segment has an entry in the segment table, and the base address of the segment is found in this item. , plus the offset, so you can find the address in the physical memory, as shown in the figure below:

 If we want to access the virtual address at offset 500 in segment 3, we can calculate the physical address as: 7000(segment 3 base address) + 500(offset) = 7500.

The segmentation method is very good, and it solves the problem that the program itself does not need to care about the specific physical memory address, but there are also some shortcomings:

  • memory fragmentation problem
  • Inefficient memory swapping

The memory fragmentation problem caused by segmentation

Suppose there is 1 G of physical memory, and the user executes multiple programs, among which:

  • The game takes up 512MB of memory
  • The browser takes up 128MB of memory
  • Music takes up 256 MB of memory

At this time, if we close the browser, there is still 1024-512-256 = 256MB of free memory.

If the 256MB is not continuous, it is divided into two sections of 128MB memory, which will result in no space to open another 200MB program.

Does memory fragmentation cause memory fragmentation?

 Memory fragmentation is mainly divided into: internal memory fragmentation and external memory fragmentation

Memory segmentation management can allocate memory according to actual needs, so as many segments are allocated as there are needs, so there will be no internal memory fragmentation .

However, since the length of each segment is not fixed, multiple segments may not be able to use all the memory space exactly, and multiple discontinuous small physical memories will be generated, resulting in the inability to load new programs, so the problem of external memory fragmentation will occur .

The solution to the problem of [external memory fragmentation] is memory swapping.

You can write the 256MB memory occupied by the music program to the hard disk, and then read it back into the memory from the hard disk. However, when reading it back, it cannot be loaded to the original location, but closely follows the already occupied 512MB memory. In this way, a continuous 256MB memory space can be vacated, so the new 200MB program can be loaded.

This memory swap space, in the Linux system, is also the Swap space that is often seen. This space is divided from the hard disk and is used for the space exchange between the memory and the hard disk.

The problem of low memory exchange efficiency caused by segmentation

For a multi-process system, external memory fragmentation is easy to occur by using segmentation. If external memory fragmentation occurs, the Swap memory area must be re-swap. This process will cause performance bottlenecks.

Because the access speed of the hard disk is much slower than that of the memory, every time the memory is swapped, a large piece of continuous memory data needs to be written to the hard disk.

Therefore, if the memory is swapped, a program that takes up a lot of memory space is swapped, and the whole machine will appear to be stuck.

In order to solve the problem of [external memory fragmentation and low memory exchange efficiency] of memory segmentation, memory paging appears.


paging

The advantage of segmentation is that it can generate continuous memory space, but there will be problems of [external memory fragmentation and memory exchange space too large].

To solve these problems, it is necessary to come up with ways to reduce memory fragmentation. In addition, when memory swapping is required, less data needs to be written or loaded from disk, which solves the problem. This method is memory paging

Paging is to cut the entire virtual and physical memory space into segments of fixed size . Such a continuous and fixed-size memory space is called a page . Under Linux, the size of each page is 4KB .

 The virtual address and the physical address are mapped through the page table, as shown in the figure:

 The page table is stored in memory, and the memory management unit (MMU) does the work of converting virtual memory addresses into physical addresses.

When the virtual address accessed by the process cannot be found in the page table, the system will generate a page fault exception , enter the system kernel space to allocate physical memory, update the process page table, and finally return to the user space to resume the operation of the process.

How does paging solve the problem of [external memory fragmentation and inefficient memory swapping]?

Memory paging is because the memory space is pre-divided, and there will be no memory with a very small gap between segments like memory segmentation, which is why segmentation will generate external memory fragments. With pagination, the pages are tightly arranged, so there will be no external fragmentation.

However, because the smallest unit of memory allocated by the memory paging mechanism is one page, even if it is less than one page size, we can only allocate at least one page, so there will be memory waste in the page, so there will be internal memory fragmentation for the memory paging mechanism

If there is not enough memory space, the operating system will release the [not recently used] memory pages in other running processes, that is, temporarily write them on the hard disk, which is called swap out (wap out ) . Once it is needed, it is loaded again, which is called swap in . Therefore, only a few pages or a few pages are written to the disk at one time, which does not take too much time, and the efficiency of memory exchange is relatively high .

Furthermore, the paging method makes it no longer necessary to load all programs into physical memory at one time when loading programs. After mapping the pages of virtual memory and physical memory, we can not really load the page into physical memory, but only when the program is running, we need to use the instructions and data in the corresponding virtual memory page , and then loaded into physical memory .

Under the paging mechanism, how are virtual addresses and physical addresses mapped?

Under the paging mechanism, the virtual address is divided into two parts, the page number and the offset within the page . The page number is used as the index of the page table. The page table contains the base address of the physical memory where each page of the physical page is located. The combination of this address and the offset within the page forms the physical memory address, as shown in the following figure:

Summary: For a memory address translation , there are actually three steps :

  • Divide the virtual memory address into page numbers and offsets
  • According to the page number, query the corresponding physical number from the page table
  • Take the physical page number directly and add the previous offset to get the physical memory address.

But put it in the actual operating system, such a simple paging must be problematic.

The pitfalls of simple pagination

There are spatial deficiencies.

Because the operating system can run a lot of processes at the same time, this means that the page table will be very large.

In a 32-bit environment, the virtual address space is 4 GB, assuming that the size of a page is 4KB, then about 1 million pages are needed, and each [page table entry] needs four bytes to store, then the entire 4GB Space mapping requires 4MB of memory to store page tables.

The 4MB page table does not seem very large, but you must know that each process has its own virtual address space, that is to say, it has its own page table. Then, if there are 100 processes, 400MB of memory is required to store the page table, which is already a very large memory, let alone a 64-bit system.


multi-level page table

To solve the above problem, a solution called multi-level page table is needed. ( It can be understood as grouping single-level page tables. In the following example, every 1024 single-level pages are grouped. If a certain group of page table entries is not used, there is no need to create a secondary page table for this group. , saving the total space of the page table )

As we have seen before, for the implementation of a single page table, in an environment of 32 bits and a page size of 4KB , the page table of a process needs to hold more than 1 million [page table entries], and each page table entry It occupies 4 bytes in size, so it is equivalent to each page table taking up 4MB of space.

We divide the single-level page table with more than 1 million [page table entries] into pages, and divide the page table (first-level page table) into 1024 pages (secondary page table), and each table (secondary page table) Contains 1024 [page table entries], forming a secondary page :

The second-level table is divided, and the memory of 4KB (first-level page table) + 4MB (secondary page table) is required to map the 4GB address space. Doesn’t this take up more space?

 If 4GB of virtual addresses are mapped to physical memory, the second-level paging takes up more space, but we often don't allocate that much memory for a process.

Each process has 4GB of virtual address space, and obviously for most programs, the space used is far less than 4GB, because there will be some corresponding page table entries that are empty and not allocated at all. If there is a page table entry that has not been accessed for a certain period of time recently, the operating system will swap out the page to the hard disk when the physical memory is tight, that is to say, it will not occupy the physical memory.

If second-level paging is used, the first-level page table can cover the entire 4GB virtual address space, but if the page table entry of a certain first-level page table is not used, there is no need to create a second-level page corresponding to this page table table, that is, the secondary page table can be created only when needed . Do a simple calculation, assuming that only 20% of the level 1 page table entries are used, then the memory space occupied by the page table is only 4KB (level 1 page table) + 20%*4MB (level 2 page table) = 0.804MB , which saves a lot of space compared to the 4MB of a single-level page table.

Why can't the non-leveled page table save memory in this way?

From the nature of the page table, the responsibility of the page table stored in memory is to translate virtual addresses into physical addresses. If the virtual address cannot find the corresponding page table entry in the page table, the computer system will not work. Therefore, the page table must cover the entire virtual address space. A non-hierarchical page table needs more than 1 million page table entries to map, while a second-level page table only needs 1024 page table entries (at this time, the first-level page table covers The entire virtual address space is occupied, and the secondary page table is created when needed)

For 64-bit systems, two-level paging is definitely not enough, so it becomes a four-level directory, which are:

  • Global Page Directory Entry PGD
  • Upper level page directory item PUD
  • Intermediate Page Directory Item PMD
  • Page table entry PTE

TLB

Although the multi-level page table solves the problem of space, the first conversion from virtual address to physical address requires a few more conversion processes, which obviously reduces the conversion speed of these two addresses, that is, it brings time overhead. .

The program is localized , that is, within a period of time, the execution of the entire program is limited to a certain part of the program. Correspondingly, the storage space accessed by the execution is also limited to a certain memory area.

We can take advantage of this feature to store the most frequently accessed page tables in hardware with faster access speed , so in the CPU chip, a cache is added to store the most frequently accessed page table entries of the program. This cache is TLB , usually called page table cache, forwarding bypass cache, fast table, etc.

In the CPU chip, a memory management unit (MMU) chip is packaged, which is used to complete address translation and TLB access and interaction

With the TLB, when the CPU is addressing, it will first check the TLB, and if it is not found, it will continue to check the regular page table.

The hit rate of the TLB is actually very high, because there are only a few pages most frequently accessed by the program.


segment page memory management

Memory segmentation and memory paging are not opposites. They can be combined and used in the same system. After combination, they usually become segment page memory management .

Segment page memory management implementation:

  • First divide the program into multiple logical segments, which is the aforementioned segmentation mechanism
  • Then divide each segment into multiple pages, that is, the continuous space divided by the segment, and then divide the pages of fixed size

In this way, the address structure consists of three parts: the segment number , the page number in the segment , and the displacement in the page .

The data structure used for segment page address translation is a segment table for each program, and a page table for each segment. The address in the segment table is the starting address of the page table, and the address in the page table is the address of a certain page. Physical page number, as shown in the figure:

To obtain the physical address in segment page address translation, three memory accesses are required:

  • Access the segment table for the first time to get the start address of the page table;
  • Access the page table for the second time to get the physical page number
  • The third time combines the physical page number with the displacement within the page to obtain the physical address.

The method of combining software and hardware can be used to realize the conversion of segment page addresses, which increases the cost of hardware and system overhead, but improves the utilization rate of memory.


 Linux memory layout

History of Intel processors

 

Early intel processors started using segmented memory management from the 80286. But it was quickly discovered that segment memory management without page memory management is not enough, which will make the X86 series lose its competitiveness in the market. Therefore, paging memory management was implemented in the 80386 not long after. In other words, 80386 not only completes and perfects the segment memory management starting from 80286, but also implements page memory management.

  

However, when the 80386 page memory management is designed, it does not bypass segment memory management, but is based on segment memory management, which means that the function of page memory management is determined by segment memory management. A layer of address mapping is added to the mapped address .

At this time, the address mapped by the segment memory management is no longer a physical address, and Intel calls it a linear address (also called a virtual address). Therefore, the segment memory management first maps the logical address to a linear address, and then Then the paging memory management maps the linear address into a physical address.

  • The address used by the program is usually an address that is not mapped by segment memory management, called a logical address
  • Addresses mapped through segmented memory management are called linear addresses or virtual addresses

Linux memory mainly uses paging memory management, but at the same time it inevitably involves the segment mechanism .

 This is mainly caused by the development history of the above-mentioned Intel processors, because Intel X86 CPUs always perform segment mapping on the addresses used in the program before performing page mapping.

But in fact, the approach taken by the Linux kernel is to make the segment mapping process actually useless.

Each segment in the Linux system has the entire 4GB virtual space starting from address 0 (in a 32-bit environment), that is, the starting addresses of all segments are the same. This means that the code in the Linux system, including the code of the operating system itself and the application program code, is faced with a linear address space (virtual address). Concept, segments are only used for access control and memory protection.

How is Linux's virtual address space distributed?

In the Linux operating system, the interior of the virtual address space is divided into two parts, the kernel space and the user space. Systems with different bits have different address space ranges. For example, common 32-bit and 64-bit systems, as shown in the following figure:

 It can be seen here:

  •  The kernel space of the 32-bit system occupies 1G, which is at the highest point, and the remaining 3G is user space
  • The kernel space and user space of the 64-bit system are both 128T, occupying the highest and lowest parts of the entire memory space respectively, and the remaining middle part is undefined.

The difference between kernel space and user:

  • When the process is in user mode, it can only access user space memory
  • The memory in the kernel space can only be accessed when entering the kernel state

Although each program has its own independent virtual address, the kernel address in each virtual memory is actually associated with the same physical memory , so that after the process switches to the kernel state, it can easily access the kernel space Memory.

 

To further understand the division of virtual space, user space and kernel space are divided in different ways .

Taking the 32-bit operating system as an example, the user space distribution is shown in the figure:

 From this picture, you can see that the user space memory is divided into 6 different memory segments from low to high :

  • Code segments, including binary executable code
  • The data segment, including initialized static constants and global variables
  • BSS segment, including uninitialized static variables and global variables
  • Heap segments, including dynamically allocated memory, start at low addresses and grow upwards
  • File mapping segments, including dynamic libraries, shared memory, etc., grow upwards from low addresses
  • The stack segment, including local variables and the context of function calls, etc. The size of the stack is fixed, usually 8MB. Of course, the system also provides parameters so that we can customize the size;

As can be seen from the memory layout in the above figure, there is still a section of memory space (gray part) under the code segment. This area is [reserved area]. The reason why there is a reserved area is because in most systems, we think it is relatively small The address of the value is not a valid address. For example, we usually assign invalid pointers to NULL in C code. Therefore, there will be an inaccessible memory reserved area here to prevent the program from reading or writing data at some small memory addresses due to bugs.


Summarize

In order to keep the memory addresses between processes unaffected and isolated from each other in a multi-process environment, the operating system allocates a separate set of virtual memory addresses for each process , and each program only cares about its own virtual address. In fact, everyone's virtual address is the same, but the physical memory address distributed is different.

Each process has its own virtual space, but there is only one physical memory, so when a large number of processes are enabled, the physical memory will inevitably be very tight, so the operating system will temporarily store the infrequently used memory to the hard disk through memory swapping technology ( swapped out ), and loaded back into physical memory when needed ( swapped in ).

Now that there is a virtual memory address, it is necessary to [map] the virtual address to the physical address. This process is usually maintained by the operating system.

Then, for the mapping relationship between virtual addresses and physical addresses, there can be paging and segmentation , and a combination of the two [ segment page type ] can also be used.

Memory segmentation is divided into stack segment, heap segment, data segment, code segment, etc. according to the logical point of view of the program, so that segments with different attributes can be separated, and at the same time it is a continuous space. But the size of each segment is not uniform, which will lead to problems of external memory fragmentation and low memory exchange efficiency .

Therefore, memory paging appears , which divides the virtual space and physical space into pages of fixed size . For example, in the Linux system, the size of each page is  4KB. Since the page is divided, there will be no small memory fragments, which solves the problem of external memory fragmentation of memory segmentation. At the same time, when the memory is swapped, only one or several pages are written to the hard disk, which greatly improves the efficiency of memory swapping.

In order to solve the problem of too large page table generated by simple paging , there is a multi-level page table , which solves the problem of space, but this will cause the CPU to need many layers of tables to participate in the process of addressing, adding Big time overhead. Therefore, according to the principle of program locality, a TLB is added to the CPU chip  , which is responsible for caching the recently frequently accessed page table entries, which greatly improves the address conversion speed.

The Linux system mainly uses paging management, but due to the development history of Intel processors, the Linux system cannot avoid segment management . So Linux sets the base address of all segments  0, which means that the address space of all programs is a linear address space (virtual address), which is equivalent to shielding the concept of CPU logical addresses, so segments are only used for access control and memory protection.

In addition, the virtual space distribution in the Linux system can be divided into two parts: user state and kernel state , among which the distribution of user state: code segment, global variable, BSS, function stack, heap memory, and mapping area.

Guess you like

Origin blog.csdn.net/qq_48626761/article/details/131983555