【问题标题】:Contents of allocated memory in WindowsWindows 中分配内存的内容
【发布时间】:2014-06-26 15:37:15
【问题描述】:

我玩过 C 和不同的排序算法。我决定先尝试声明一个具有一定大小(例如 100)的自动数组而不初始化它,而不是生成一个随机数组进行排序。我预计操作系统(我在 Windows XP 上)会在其中输入零,否则可能是其他进程留下的一些数据。但事实证明,这种未初始化的数组中没有零。所以第一个问题是:它可能是什么数据,为什么不被操作系统清理?会不会是我正在运行编译器和程序的“cmd”shell的垃圾?

接下来,由于我尝试的排序算法不再分配任何内存,而是全部排序,我认为有两种可能性:(a)为数组分配的内存区域将被排序并在下一次运行时保持这种状态,或者(b)在下一次运行时,操作系统会给程序另一部分内存,因此会产生另一个垃圾。但事实证明,两者都不是。无论我对它进行多少次排序,内存都保持不变。那么,第二个问题是:我怎么可能得到一些随机的虚拟内存区域,对它进行排序,然后在下一次运行时得到原始形式的相同区域?

下面是代码和我的步骤。

#include <stdio.h>
#define SIZE 100

void quick_sort( int *a, size_t size )
{
     /* No comments here, everybody knows quicksort
     and anyone will write it better! :) */

     if( size <= 1 ) return;

     int tmp, pivot;
     int small_length, pivot_pos;

     pivot_pos = size / 2;
     pivot = a[pivot_pos];
     tmp = a[0];
     a[0] = pivot;
     a[pivot_pos] = tmp;

     small_length = 0;

     for( int i = 1; i < size; i++ )
     {
      if( a[i] < pivot ){
           small_length++;
           tmp = a[small_length];
           a[small_length] = a[i];
           a[i] = tmp;
      }
     }

     a[0] = a[small_length];
     a[small_length] = pivot;

     quick_sort( a, small_length );
     quick_sort( a + small_length + 1, size - small_length - 1 );
}

int main( int argc, char *argv[] )
{
     int a[SIZE];
     int i;

     quick_sort( a, SIZE );
     for( i = 0; i < SIZE; i++ ) {
        printf( "%d\n", a[i] );
     }
     return 0;
}

我使用的步骤:

  1. 使用注释的quick_sort 调用编译,查看未排序的未初始化数组:cc sort.c -Wall -std=c99 &amp;&amp; a &gt; unsorted1(编译后的可执行文件为a.exe)。
  2. 取消注释quick_sort 调用并查看排序结果:cc ... &gt; sorted
  3. 再次评论调用以再次查看未排序的数组:cc ... &gt; unsorted2
  4. 比较文件 unsorted1unsorted2 - 它们是相同的,都是 100 行。

我也试过启动另一个“cmd”实例,数据是一样的。

更新

我。未排序数据的十六进制转储:

0000000 0000 0000 fd7c 0022 fd74 0022 fdd8 0022
0000020 0170 0000 1448 7c91 ffff ffff 1440 7c91
0000040 0000 0024 13d2 7c91 301c 0024 3008 0024
0000060 0010 0000 b988 7c97 0000 003e 0007 0000
0000100 fd24 0022 0000 0000 fe24 0022 e900 7c90
0000120 0040 0001 002e 0000 0000 003e eeeb 7c80
0000140 fe30 0022 e900 7c90 0040 7c91 ffff ffff
0000160 003d 0001 0002 0000 fd5c 0022 0000 0000
0000200 fe50 0022 0002 0000 0002 0000 ffff ffff
0000220 003d 7c91 c2de 77c1 0000 003e 0000 0000
0000240 c2e3 77c1 a122 0040 0000 0000 2bc4 003e
0000260 2070 77c0 ffff ffff 0000 003e 2bc0 003e
0000300 0004 0000 2373 0024 1660 0040 fea0 0022
0000320 c024 77c1 0000 003e 0000 0000 c02d 77c1
0000340 1660 0040 2373 0024 1dc0 0040 fec0 0022
0000360 c024 77c1 0000 003e 0000 0000 c02d 77c1
0000400 1dc0 0040 2373 0024 0000 0000 5c94 77c2
0000420 a52e 77c2 1ae8 77c5 fedc 0022 9d60 77c2
0000440 fe88 0022 4e2f 77c2 feec 0022 5c94 77c2
0000460 a52e 77c2 1ae8 77c5 fefc 0022 9d60 77c2
0000500 0008 0000 4e2f 77c2 4e29 77c2 ff3c 0022
0000520 2373 0024 0000 0000 1dc0 0040 fed4 0022
0000540 ff08 0022 ffe0 0022 5c94 77c2 2850 77c0
0000560 ffff ffff 4e29 77c2 4e42 77c2 1dc0 0040
0000600 ffa0 0022 1e1e 0040 1dc0 0040 0020 0000

为了生成转储,我必须在代码中添加一个 FILE、fopen(...)、fclose(...),这会改变输出。但是这些调用是在数组声明之后进行的,所以仍然不确定这会如何影响数组的内容。

二。尝试将 SIZE 增加到 10000 并最终看到零。输出是许多零,最后是那个熟悉的垃圾。我不确定内存增长的方向是什么,我希望数据保持在数组的开头...

【问题讨论】:

  • 向我们展示 unsorted1 的十六进制内容 - 很可能分配器用 0xDEADBEEF 之类的东西填充它(不过我怀疑是更现代的版本......)
  • 操作系统不会给你的程序一块被其他进程释放的内存,这将是一个严重的信息泄露安全漏洞。内存只是在调用 main() 之前执行的程序的 C 运行时库启动(全局构造函数、stdio 初始化等)早期的剩余堆栈垃圾。

标签: c windows memory


【解决方案1】:

现代的多用户/多进程操作系统总是将干净的内存页面交给请求内存的进程(这样敏感数据就不会从一个进程泄漏到另一个进程)。请注意,此“干净”合同仅在操作系统最初将内存移交给进程时才适用。如果进程最初将内存用于一件事,然后再用于其他事情,则不会自动重新清理内存。这就是这里发生的事情 - 您的未初始化变量在堆栈上,并且在 main 运行之前,C 运行时启动代码已经使用了堆栈。您会看到堆栈中留下的任何垃圾启动代码。如果您想知道它到底是什么,您可以阅读 Microsoft Visual C 运行时库源代码(它随 Visual Studio 提供)或查看反汇编程序中程序入口点的反汇编。

这同样适用于堆。当mallocVirtualAlloc等第一次从操作系统获取页面时,它们将是干净的。但是当您调用freeVirtualFree 等时,运行时库没有义务将页面返回给操作系统并重新请求它们。它可以只保留它们(无需清理它们)并使用它们来满足以后的请求。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多