Windows 中分配的内存内容

标签 c windows memory

我尝试了 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 && a > unsorted1 (编译后的可执行文件为a.exe)。
  2. 取消注释 quick_sort 调用并查看排序结果:cc ... >排序
  3. 再次注释该调用以再次查看未排序的数组:cc ... > 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,最后看到了零。输出是许多零,最后是熟悉的垃圾。我不确定内存增长的方向,我希望数据保留在数组的开头......

最佳答案

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

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

关于Windows 中分配的内存内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23555417/

相关文章:

关于 fgets() 函数字符限制的 C 编程?

c - 读取 int 类型时如何不读取 scanf 中的 float 类型

当我运行 C 程序并按暂停键时,C 程序显示它卡在函数调用上

windows - 我应该为 Windows 7 分区留出多少空间?

windows - 如何安装 libgpuarray Windows

c - Visual Studio : Different Size in Memory for same executable in XP and Windows7

c - 在中止之前将 shell 传递给 child

c - Linux 中是否有 API 可以从语言环境中获取完整的语言名称?

c - 没有 MMU 的内存保护

c++ - 用于小型未对齐数据的快速 memcpy