0

每个进程获得 4 GB 的虚拟地址空间,在 4 GB 之外,用户空间获得 2 GB。在这 2 GB 中,我想读取操作系统分配给进程的整个内存堆栈。

char chrArray[2000000];假设我在堆栈上声明了一个大小为 2000,000 ( ) 的本地数组。我想问几个问题。

1)使用gccand cygwin,我可以在不初始化的情况下读取它的内容,但它的内容大部分是空的(我曾经%c将数组打印到文件中)或者这个数组末尾的一些垃圾数据。我在垃圾数据中提取了一个字符串,并在内存转储中查找它(使用DumpIt工具获取),但内存转储中不存在此字符串。

我的问题是这些垃圾数据是从哪里来的?它是否位于硬盘中?

2)我想用fork()在每个子进程中声明char数组,但我猜,它复制父进程的整个地址空间并使用Copy-on-Write技术,所以它似乎没有用。我对这种解释是否正确?

3)我想要的是声明一个大数组,并且每次映射到一些新的物理内存地址。这是否可以实现,如果可以,如何实现?

通过重复这个过程,我想扫描整个内存。

我多次尝试bash脚本来运行这个程序,但它总是从相同的虚拟基地址开始。

我试图运行一个for声明(比如说)10个字符数组的循环,但是通过打印它们的基地址,我看到所有数组的地址都相同。

我正在使用Windows 7C编程,我认为我缺乏一些必需的操作系统知识。

谢谢。

PS如果有人好奇我为什么要这样做,我正在这方面进行研究。

4

2 回答 2

2

为了避免安全问题,当分配物理页面时,大多数内核确保物理页面不包含数据(例如用零填充)。否则,一个进程可以用敏感信息(例如密码)填充页面然后释放它,而另一个进程可以分配该页面并访问敏感数据。

因此,您在阵列中看到的垃圾就是您自己的垃圾。

当一个进程刚开始时,很多事情通常在main()获得控制之前发生。这些事情可能包括动态链接和设置系统库、执行构造函数(用于 C++)等。这意味着在代码运行之前,事情会被放入堆栈(然后从堆栈中删除)。这是你看到的垃圾。

于 2012-10-14T01:47:06.317 回答
2

假设我声明了一个大小为 2000,000 ( char chrArray[2000000];)的本地数组

这是危险的。如果你用完了堆栈,你的程序就会崩溃。

该数组末尾的一些垃圾数据。

堆栈向下增长,因此数组的末端(较高的部分)对应于堆栈的较旧部分。当你的程序启动时,数据被清零,当你的程序运行时,它会将数据写入堆栈。因此,“垃圾数据”只是剩余的局部变量和您调用的函数的其他堆栈帧。(大多数操作系统使用专门的写时复制技术将您的进程内存归零——我说“专门”是因为当您知道整个块为零时,复制一块内存很容易。)

它是否位于硬盘中?

硬盘中的数据只会故意显示在您的内存空间中。当您的进程重用另一个进程的内存时,首先将内存清零。

我想过使用 fork() 在每个子进程中声明 char 数组,但我猜它会复制父进程的整个地址空间并使用 Copy-on-Write 技术,所以它似乎没有用。我对这种解释是否正确?

fork()这被标记为 Windows,除非您使用 Cygwin ,否则它没有。我不知道 Cygwin 的实现。我不确定你想要完成什么,或者你期望什么,但这正是fork()应该如何表现的。该fork()调用复制了整个过程,包括内存。

我想要的是声明一个大数组,并且每次它都映射到一些新的物理内存地址。这是否可以实现,如果可以,如何实现?

用户空间程序不能使用物理内存地址,只能使用虚拟内存地址。不,这是不可能的。

更糟糕的是,假设您char arr[10000]在虚拟地址 1000 分配了一个数组,并假设虚拟地址 1000 对应于物理地址 6000。

  • 的地址&arr[0]是虚拟地址 1000 和物理地址 6000... 除非您的进程被换出,此时它根本没有物理地址。所以物理地址并不总是存在。

  • 当您的进程被换回时,&arr[0]仍然是虚拟地址 1000,但它可能是物理地址 6000 或 8000 或 999000 ......谁知道呢?

  • 的地址&arr[1000]始终是虚拟地址 2000,但它可能是物理地址 10000 或 85000 或完全不同的地址……谁知道呢?

进一步阅读:您可能希望阅读有关操作系统的“虚拟内存”子系统的信息。

于 2012-10-14T01:50:51.230 回答