- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
从书上看到当一个进程启动时,它的私有(private)进程地址空间被创建
假设它是从 0x0 到 0xMAX
还有一部分空间是堆,我们写了一个for循环继续malloc(1k date)直到返回false。它分配了 3GB 的数据。
那么问题来了,如果一开始就分配了0x0到0xMAX,那说明0x0到0xMAX从一开始就大于3GB(因为有stack,control...)?
如果一开始一个进程可以占用超过3GB,那一定是我理解错了。
谁能解释一下这个 0x0 - 0xMAX 是如何存储在乞讨中的?
最佳答案
通常,将可执行文件加载到内存是由 linux 加载程序 ld 驱动的。例如,如果我创建一个非常简单的 C 程序,可以说:
void main {}
用gcc编译这个程序后,我们得到一个可执行文件(ELF格式)a.out。如果我们通过运行 ldd 来分析这个非常简单的程序的依赖关系,我们会发现:
linux-gate.so.1 => (0x00545000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x00ccb000)
/lib/ld-linux.so.2 (0x00594000)
第一个linux-gate.so被内核暴露出来进行系统调用。 ld-linux.so 实际上是 linux 加载器。它负责在内存中加载任何可执行文件并运行它。如果我们查看生成的 a.out(例如使用 hexedit 工具),我们可以看到它的 header 包含对 ld-linux 所在位置的引用:
.ELF........................4...8.......
4. ...(.........4...4...4... ... .......
........T...T...T.......................
........................................
........................(...(...(.......
................h...h...h...D...D.......
....P.td............4...4...........Q.td
............................R.td........
..................../lib/ld-linux.so.2..
............GNU.........................
....GNU....F*QLk$,.....)..Yl............
一旦您启动该进程,ld-linux 加载程序首先检查您需要(依赖)哪些共享库以及它们是否可用。如果你依赖一些不可用的共享库,ld-linux 将不会加载进程(ld-linux 会查看你的 LD_LIBRARY_PATH env 变量,/etc/ld.so.cache 文件,最后在默认路径中:/lib 和/usr/lib(man ld-linux 了解更多信息)。
一旦 ld-linux 确保所有的库都在那里,它就会分配内存来加载进程。通常一个可执行文件有几个段,为简单起见,我们可以将它们简化为文本(代码)、bss(未初始化数据)、数据(初始化和静态数据)。当进程被加载到内存中时,加载程序会保留保存所有这些部分所需的内存量,并将进程所依赖的所有共享库映射到进程的虚拟空间中。可以查看linux中某个进程的映射表列表:
cat /proc/pid_of_process/maps
如果我运行上面简单程序的修改版本(通过添加对 usleep 的调用以获取进程 pid)并检查其映射,我们得到以下内容(_ 只是为了隐藏真实路径,其中我的家出现了):
003a5000-003a6000 r-xp 00000000 00:00 0 [vdso]
0075a000-008fd000 r-xp 00000000 08:03 2137894 /lib/i386-linux-gnu/libc-2.15.so
008fd000-008ff000 r--p 001a3000 08:03 2137894 /lib/i386-linux-gnu/libc-2.15.so
008ff000-00900000 rw-p 001a5000 08:03 2137894 /lib/i386-linux-gnu/libc-2.15.so
00900000-00903000 rw-p 00000000 00:00 0
00e4a000-00e6a000 r-xp 00000000 08:03 2137906 /lib/i386-linux-gnu/ld-2.15.so
00e6a000-00e6b000 r--p 0001f000 08:03 2137906 /lib/i386-linux-gnu/ld-2.15.so
00e6b000-00e6c000 rw-p 00020000 08:03 2137906 /lib/i386-linux-gnu/ld-2.15.so
08048000-08049000 r-xp 00000000 08:05 3589145 /______________/test/a.out
08049000-0804a000 r--p 00000000 08:05 3589145 /______________/test/a.out
0804a000-0804b000 rw-p 00001000 08:05 3589145 /______________/test/a.out
b771f000-b7720000 rw-p 00000000 00:00 0
b7745000-b7747000 rw-p 00000000 00:00 0
bf884000-bf8a5000 rw-p 00000000 00:00 0 [stack]
这实际上是进程的虚拟内存映射。这些页面被映射到物理内存,每个进程都有自己的 PMT(程序映射表),用于在虚拟地址和物理地址之间进行转换。通常,进程内存具有以下布局:
(来自 http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory/)
因此,考虑到这些信息并回到您最初的问题,
So, question, if 0x0 to 0xMAX is allocated in the beginning, it means 0x0 to 0xMAX is larger than 3GB (since there are stack, control...) since the beginning?
答案是没有这样的保留。加载程序保留运行进程所需的物理内存。之后,根据进程需求(动态内存分配)及其行为,其堆和堆栈区域可能会增大或缩小。每次进程需要访问一些实际不存在于物理内存中的内存(虚拟)时,都会发出页面错误,并将该页面从磁盘加载到物理内存中的保留位置。有时为了做到这一点,内核必须将属于另一个进程的一些页面换出到磁盘。物理内存是一种有限的资源,操作系统必须正确处理它才能提供所有正在运行的进程。
通过这种策略,linux 内核能够运行多个进程,其中每个进程通常在物理内存中拥有 4GB(32 位系统)的虚拟内存(特别是在过去)。通常,即使您动态保留内存(例如使用 malloc),调用也会成功,但实际上您还没有保留此物理内存。一旦它尝试使用它(通过读取或写入此内存),您的进程就会得到它。
这可能是一个很长的答案。我希望我没有错过很多细节,希望它能帮助您理解 Linux 中进程内存的剖析。
关于linux - "linux process address space"是如何存储的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32746996/
我系统上的docker info命令输出如下: # docker info Containers: 0 Images: 0 Storage Driver: devicemapper ..... D
我如何捕获用户按下 ctrl + space + space? 我用这段代码成功测试了ctrl + space: RegisterHotKey(0, 1, MOD_CONTROL, VK_SPACE)
我有一个 Matlab 图,我想在论文中使用。此图包含多个 cdfplots。现在的问题是我不能使用标记,因为在情节中变得非常密集。如果我想让样本稀疏,我必须从 cdfplot 中删除一些样本,这将导
我正在尝试获取我将用于备份的服务器上所有数据库的列表。以下是我尝试打印数据库列表但出现错误的代码片段。如何解决?添加双方括号并不能解决问题。 我已经研究了一些类似的问题,但我无法弄清楚。 grep:字
我了解 new gen/old gen/perm gen 之间的区别,但我不知道“To Space”和“From Space”是什么。我看到我的“From Space”使用率达到 99.8%,而“To
我当前有一个返回时看起来像这样的字符串: //This is the url string // the-great-debate---toilet-paper-over-or-under-the-r
我太亲密了。我正在尝试编写用于Notepad++的正则表达式表达式,以用空格替换破折号,而忽略已经用前置/后置空格代替的破折号。我知道我可以用“foobarfoo”搜索/替换“-”,然后搜索“-”替换
我的 ANTLR 代码如下: LPARENTHESIS : ('('); RPARENTHESIS : (')'); fragment CHARACTER : ('a'..'z'|'0'..'9'|)
在过去的 6 个小时里,我一直在尝试在我的 webgl 应用程序中实现点击,但我找不到任何关于这个主题的足够清晰的内容。 到目前为止,我想出的是伪代码: screenSpace = mousePosi
如何使用正则表达式来测试空格或制表符,但不测试换行符? 我尝试了 \s,但我发现它也测试换行符。 我使用C# (.NET) 和 WPF ,但这应该不重要。 最佳答案 使用字符类:[\t] 关于rege
我想解析以下内容: name:name 名称以字母开头和结尾,并且可以包含字母和空格的任意组合。它们也可以是空白的。我的规则是: identifier = alnum (space* alnum)*;
有什么办法可以让 Eden 空间按比例大于 Tenured 空间吗?有 NewRatio 但它以相反的方式工作(Tenured 比 Eden 大几倍)。 我知道有 -XX:NewSize= 和 -XX
我正在编写一个程序,让人们输入他们的信息(姓名,年龄......)。对于姓名输入,我不希望他们留空,只允许字母和空格,但不能以空格开头。合适的正则表达式是什么?我尝试使用: ^[a-zA-Z\\s]*
好的,我正在制作一个程序,它也可以制作垂直线、水平线和对角线!我对我的一个没有任何意义的输出感到困惑。 所以我的伪代码是这样的: //enter a char //enter a number
当我使用 scp 从服务器复制文件时, 我错误地使用了命令 scp xxx@xxxx:xx.zip . 当我完成后,我发现该文件的名称是 .我无法解压 这是目录列表。 http://pfil
我需要一个 bat 文件来获取 Windows 系统中 C:\驱动器的总空间和可用空间(以 GB(千兆字节)为单位),并创建一个包含详细信息的文本文件。 注意:我不想使用任何外部实用程序。 最佳答案
作为预处理我的数据的一部分。我希望能够替换空格后跟数字,同时保留空格后跟一个字符。例如: Input String: '8.1.7 Sep 2000 Dec 2004 Dec 2006 Indefin
我正在编写一个 XPath 表达式,但我修复了一个奇怪的错误,但是以下两个 XPath 表达式之间有什么区别? "//td[starts-with(normalize-space()),'Posted
在 C 中,当读取文本文件时,是否有可能接受一个未知大小的整数值(假设它适合 int),因为它在数字之前和数字之后都有一个空格。例如。 363 865我想分别存储 363 和 865,因为它们有自己的
在 sys/ptrace.h 中,我看到类似这样的内容: @define PT_READ_I 1 /* read world in child's I space*/ @define PT_READ
我是一名优秀的程序员,十分优秀!