Heim  >  Artikel  >  System-Tutorial  >  So funktioniert die Speicherzuweisung unter Linux

So funktioniert die Speicherzuweisung unter Linux

WBOY
WBOYnach vorne
2024-02-10 16:00:26508Durchsuche

Es ist wichtig, die Details der Linux-Speicherzuweisung zu verstehen, insbesondere im Kernel und in der Systemarchitektur. Werfen wir einen tiefen Einblick in die Linux-Speicherzuweisung und verstehen, was sich hinter den Kulissen abspielt.

Damit ein Prozess auf einem Computer ausführbar ist, muss er im Speicher abgelegt werden. Dazu muss das Feld dem Prozess im Speicher zugewiesen werden. Die Speicherzuweisung ist ein wichtiges Thema, auf das man achten muss, insbesondere in der Kernel- und Systemarchitektur.

Werfen wir einen genaueren Blick auf die Speicherzuweisung unter Linux und verstehen, was sich hinter den Kulissen abspielt.

Wie erfolgt die Speicherzuweisung?

Die meisten Softwareentwickler kennen die Details dieses Prozesses nicht. Aber wenn Sie ein Systemprogrammierer-Kandidat sind, sollten Sie mehr darüber wissen. Bei der Betrachtung des Zuordnungsprozesses ist es notwendig, ein kleines Detail über Linux und die glibc-Bibliothek zu machen.

Wenn Anwendungen Speicher benötigen, müssen sie diesen beim Betriebssystem anfordern. Diese Anfrage vom Kernel erfordert natürlich einen Systemaufruf. Sie können im Benutzermodus keinen Speicher selbst zuweisen.

**malloc()**-Funktionsreihen sind für die Speicherzuweisung in der C-Sprache verantwortlich. Hier stellt sich die Frage, ob malloc() als Glibc-Funktion einen direkten Systemaufruf durchführt.

Im Linux-Kernel gibt es keinen Systemaufruf namens malloc. Es gibt jedoch zwei Systemaufrufe für den Anwendungsspeicherbedarf: brk und mmap.

Da Sie Speicher in Ihrer Anwendung über Glibc-Funktionen anfordern, möchten Sie möglicherweise wissen, welche Systemaufrufe Glibc derzeit verwendet. Die Antwort ist beides.

Linux 上内存分配的工作原理

Erster Systemaufruf: brk

Jeder Prozess verfügt über ein kontinuierliches Datenfeld. Durch den Systemaufruf brk wird der Programmunterbrechungswert, der die Datenfeldgrenze bestimmt, erhöht und der Zuordnungsprozess ausgeführt.

Obwohl die Speicherzuweisung mit dieser Methode sehr schnell geht, ist es nicht immer möglich, ungenutzten Speicherplatz an das System zurückzugeben.

Angenommen, Sie weisen über die Funktion malloc() für den brk-Systemaufruf fünf Felder mit einer Feldgröße von jeweils 16 KB zu. Wenn Sie das zweite dieser Felder ausfüllen, kann die zugehörige Ressource nicht zurückgegeben (zugeteilt) werden, damit das System sie verwenden kann. Denn wenn Sie den Adresswert reduzieren, um anzuzeigen, wo das zweite Feld beginnt, und brk aufrufen, wird die Freigabe des dritten, vierten und fünften Felds abgeschlossen.

Um in diesem Fall Speicherverlust zu verhindern, überwacht die malloc-Implementierung in glibc den zugewiesenen Speicherort im Prozessdatenfeld und gibt ihn dann gemäß der Angabe durch die Funktion free() an das System zurück, damit das System den freien Speicherplatz für weiteren Speicher verwenden kann verteilen.

Mit anderen Worten, wenn Sie nach der Zuweisung von 5 16-KB-Bereichen die Funktion free () verwenden, um den zweiten Bereich zurückzugeben, und dann nach einer Weile einen weiteren 16-KB-Bereich anfordern, wird der vorherige Datenbereich nicht durch den brk-Systemaufruf erweitert Adresse ist zurück.

Wenn die neu angeforderte Region jedoch größer als 16 KB ist, wird die Datenregion durch Zuweisung einer neuen Region über den brk-Systemaufruf vergrößert, da Region 2 nicht verwendet werden kann. Obwohl Bereich Nummer zwei nicht genutzt wird, kann die Anwendung ihn aufgrund der unterschiedlichen Größe nicht nutzen. Aufgrund solcher Szenarien kommt es zu einer sogenannten internen Fragmentierung, bei der selten alle Teile des Speichers vollständig genutzt werden können.

Für ein besseres Verständnis versuchen Sie, die folgende Beispielanwendung zu kompilieren und auszuführen:

#include 
#include 
#include 
int main(int argc, char* argv[])
{
        char *ptr[7];
        int n;
        printf("Pid of %s: %d", argv[0], getpid());
        printf("Initial program break   : %p", sbrk(0));
        for(n=0; nprintf("After 5 x 16kB malloc   : %p", sbrk(0));
        free(ptr[1]);
        printf("After free of second 16kB       : %p", sbrk(0));
        ptr[5] = malloc(16 * 1024);
        printf("After allocating 6th of 16kB    : %p", sbrk(0));
        free(ptr[5]);
        printf("After freeing last block        : %p", sbrk(0));
        ptr[6] = malloc(18 * 1024);
        printf("After allocating a new 18kB     : %p", sbrk(0));
        getchar();
        return 0;
}

Wenn Sie die Anwendung ausführen, erhalten Sie eine Ausgabe ähnlich der folgenden:

Pid of ./a.out: 31990
Initial program break   : 0x55ebcadf4000
After 5 x 16kB malloc   : 0x55ebcadf4000
After free of second 16kB       : 0x55ebcadf4000
After allocating 6th of 16kB    : 0x55ebcadf4000
After freeing last block        : 0x55ebcadf4000
After allocating a new 18kB     : 0x55ebcadf4000
Linux 上内存分配的工作原理

Die Ausgabe von brk mit strace ist wie folgt:

brk(NULL)                               = 0x5608595b6000
brk(0x5608595d7000)                     = 0x5608595d7000

Wie Sie sehen können, wurde 0x21000 zur Endadresse des Datenfelds hinzugefügt. Sie können dies anhand des Werts 0x5608595d7000 verstehen. Es werden also ungefähr 0x21000 oder 132 KB Speicher zugewiesen.

Hier gibt es zwei Punkte zu beachten. Die erste besteht darin, mehr als im Beispielcode angegeben zuzuweisen. Die andere ist, welche Codezeile den brk-Aufruf verursacht, der die Zuweisung bereitstellt.

Randomisierung des Adressraumlayouts: ASLR

Wenn Sie die oben genannten Beispielanwendungen nacheinander ausführen, werden Ihnen jedes Mal unterschiedliche Adresswerte angezeigt. Eine zufällige Änderung des Adressraums auf diese Weise erschwert die Arbeit von Sicherheitsangriffen erheblich und erhöht die Sicherheit der Software.

但是,在 32 位架构中,通常使用 8 位来随机化地址空间。增加位数将不合适,因为剩余位上的可寻址区域将非常低。此外,仅使用 8 位组合不会使攻击者的事情变得足够困难。

另一方面,在 64 位体系结构中,由于可以为 ASLR 操作分配的位太多,因此提供了更大的随机性,并且提高了安全程度。

Linux 内核还支持基于 Android 的设备,并且 ASLR 功能在 Android 4.0.3 及更高版本上完全激活。即使仅出于这个原因,也可以说 64 位智能手机比 32 位版本具有显着的安全优势。

通过使用以下命令暂时禁用 ASLR 功能,之前的测试应用程序每次运行时都会返回相同的地址值:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

要将其恢复到以前的状态,在同一个文件中写入 2 而不是 0 就足够了。

第二个系统调用:mmap

mmap 是 Linux 上用于内存分配的第二个系统调用。通过 mmap 调用,内存中任何区域的空闲空间都映射到调用进程的地址空间。

在以这种方式完成的内存分配中,当您想使用前面 brk 示例中的 free() 函数返回第二个 16KB 分区时,没有机制可以阻止此操作。从进程的地址空间中删除相关的内存段。它被标记为不再使用并返回系统。

因为与使用 brk 相比,使用 mmap 的内存分配非常慢,所以需要分配 brk。

使用 mmap,内存的任何空闲区域都映射到进程的地址空间,因此在该进程完成之前,已分配空间的内容被重置。如果没有以这种方式进行重置,则属于先前使用相关内存区域的进程的数据也可以被下一个不相关的进程访问。这样就不可能谈论系统中的安全性。

Linux 中内存分配的重要性

内存分配非常重要,尤其是在优化和安全问题上。如上面的示例所示,不完全理解此问题可能意味着破坏系统的安全性。

甚至许多编程语言中存在的类似于 push 和 pop 的概念也是基于内存分配操作的。能够很好地使用和掌握系统内存对于嵌入式系统编程和开发安全和优化的系统架构都是至关重要的。

如果您还想涉足 Linux 内核开发,请考虑首先掌握 C 编程语言。

综上所述,Linux 中的内存分配是一个需要注意和理解的重要问题,特别是对于程序员、内核开发人员和系统架构师而言。熟练掌握内存分配可以提高软件性能和安全性,并在嵌入式系统编程和系统架构方面提供更好的支持。同时,C 编程语言的掌握也是涉足 Linux 内核开发的关键。

Das obige ist der detaillierte Inhalt vonSo funktioniert die Speicherzuweisung unter Linux. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:lxlinux.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen