VirtualMemorySize64和PrivateMemorySize64之间的区别是什么

时间:2015-03-20 14:08:23

标签: c# .net clr

我不明白Process.PrivateMemorySize64Process.VirtualMemorySize64

之间的区别

我创建了一个简单的控制台应用程序,它将10倍10兆字节分配给一个字节数组。

const int tenMegabyte = 1024*1024*10;
long allocatedMemory = 0;
List<byte[]> memory = new List<byte[]>();
for (int i = 0; i < 10; i++)
{
    allocatedMemory += tenMegabyte;
    Console.WriteLine("Allocated memory:    " + PrettifyByte(allocatedMemory));
    Console.WriteLine("VirtualMemorySize64: " + PrettifyByte(Process.GetCurrentProcess().VirtualMemorySize64));
    Console.WriteLine("PrivateMemorySize64: " + PrettifyByte(Process.GetCurrentProcess().PrivateMemorySize64));
    Console.WriteLine();
    memory.Add(new byte[tenMegabyte]);
}

PrivateMemorySize64按照我的预期工作:它以一定的大小开始,并随着分配的内存而增长。

但VirtualMemorySize64似乎在一开始就为控制台应用程序分配了大量内存(对于32位为180mb,对于64位为560mb)

32bit sample of memory allocation 32bit sample of memory allocation

问题:

  • VirtualMemorySize的PrivateMemorySize是一部分吗? 如果是这样,那么VirtualMemorySize的其余部分是什么?它只是保留内存,还是实际上是ram / page文件?
  • 为什么即使是一个简单的控制台应用程序也会分配超过500mb的VirtualMemory?
  • 如果我的应用程序使用1GB的PrivateMemorySize和20GB的VirtualMemorySize,我应该关心还是可以忽略它?
  • 为什么64位版本的程序会分配更多的VirtualMemory?

3 个答案:

答案 0 :(得分:8)

VirtualMemorySize测量您的进程使用的虚拟内存的所有。其中包括计算机上所有其他进程共享的页面。在.NET程序中,它包括操作系统,CLR,抖动和ngen-ed框架程序集。

PrivateMemorySize测量专用于您的进程的虚拟内存,并且不能被其他进程共享。在.NET程序中,它包含所有数据和任何未被编写的jitted代码。

两者都是虚拟内存测量,内部表示为处理器的数字。每4096字节的内存一个。实际的RAM使用量是一个非常不同的数字,由Process.WorkingSet表示。通常不太有用,当其他进程需要RAM时,它可以非常快速地改变,并且您需要将一些使用的内容映射出来。你的操作系统和.NET都经过优化,可以使用大量的虚拟机,在现代机器上有很多可用的虚拟机,它可以替代磁盘。

  

VirtualMemorySize的PrivateMemorySize是一部分吗?如果是这样,那么VirtualMemorySize的其余部分是什么?它只是保留内存,还是实际上是ram / page文件?

是。其余的是共享内存,如第一段所述

  

为什么即使是一个简单的控制台应用程序也会分配超过500mb的VirtualMemory?

操作系统和.NET运行时都不会使您的控制台应用程序变得很小,但仍然需要执行它们。由于它们由所有流程共享,因此您并不关心它。你也没有什么可以做的。 A&#34;大&#34;控制台应用程序通常不会添加更多的VM,除非它分配了大量内存。

  

如果我的应用程序使用1GB的PrivateMemorySize和20GB的VirtualMemorySize,我应该关心还是可以忽略它?

1GB的私人内存并不值得担心。 20GB的VM过多。 GC堆的大小是值得关注的,当它必须遍历数千兆字节的堆时,集合可能会变慢。

  

为什么64位版本的程序会分配更多的VirtualMemory?

嗯,64是2 * 32.这并不像那样大规模,64位进程仍然倾向于使用大量的 ints 。编写一个现代的64位操作系统来假设有大量的硬件资源可供使用,Win8需要8 GB的RAM才能顺利运行。

答案 1 :(得分:1)

  

VirtualMemorySize的PrivateMemorySize部分吗?

是的。除非您编写内核驱动程序,否则所有内容都是VirtualMemorySize的一部分,在这种情况下,您可能会谈论物理RAM。

  

如果这是真的,那么其余的VirtualMemorySize是什么?

  • 将DLL加载到进程中
  • 映射的文件
  • 要编译的.NET IL代码
  • 默认进程堆
  • 堆栈
  • TEB(线程环境块)和PEB(进程环境块)
  • 如果您执行P / Invoke或类似操作,C ++会堆积
  • 直接调用VirtualAlloc()
  

它只是保留的内存,还是实际上在ram / page文件中?

可以保留(不可用)或提交(准备使用)虚拟内存。保留部分既不在RAM中也不在页面文件中。

  

为什么即使是简单的控制台应用程序也会分配超过500mb的VirtualMemory?

您可以使用调试器进行查找,例如WinDbg。 这是我在64位操作系统上的.NET 4.5 32位程序(您的代码)。

0:005> .loadby sos clr
0:005> !address -summary
--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free                                     59          edb72000 (   3.714 GB)           92.86%
<unknown>                               119           ceca000 ( 206.789 MB)  70.70%    5.05%
Image                                   222           3220000 (  50.125 MB)  17.14%    1.22%
MappedFile                               15           1b7c000 (  27.484 MB)   9.40%    0.67%
Stack                                    18            600000 (   6.000 MB)   2.05%    0.15%
Heap                                     12            1e0000 (   1.875 MB)   0.64%    0.05%
Other                                     8             31000 ( 196.000 kB)   0.07%    0.00%
TEB                                       6              6000 (  24.000 kB)   0.01%    0.00%
PEB                                       1              1000 (   4.000 kB)   0.00%    0.00%

<unknown>部分包括.NET内存。在这种情况下,由于我没有C ++或VirtualAlloc()调用,因此它可能只是.em。

也有可能看到.NET当前仅使用了206个内存中的105 MB:

0:005> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x02741018
generation 1 starts at 0x0274100c
generation 2 starts at 0x02741000
ephemeral segment allocation context: none
 segment     begin  allocated      size
02740000  02741000  027afff4  0x6eff4(454644)
Large object heap starts at 0x03741000
 segment     begin  allocated      size
03740000  03741000  04193fe8  0xa52fe8(10825704)
04860000  04861000  05261020  0xa00020(10485792)
05990000  05991000  06391020  0xa00020(10485792)
06be0000  06be1000  075e1020  0xa00020(10485792)
07be0000  07be1000  085e1020  0xa00020(10485792)
08be0000  08be1000  095e1020  0xa00020(10485792)
09be0000  09be1000  0a5e1020  0xa00020(10485792)
0b070000  0b071000  0ba71020  0xa00020(10485792)
0c070000  0c071000  0ca71020  0xa00020(10485792)
0d070000  0d071000  0da71020  0xa00020(10485792)
Total Size:              Size: 0x64c20fc (105652476) bytes.
------------------------------
GC Heap Size:    Size: 0x64c20fc (105652476) bytes.

我们可以看到总共保留了131 MB:

0:005> !address -summary
--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_FREE                                 59          edb72000 (   3.714 GB)           92.86%
MEM_COMMIT                              302           a114000 ( 161.078 MB)  55.07%    3.93%
MEM_RESERVE                              99           836a000 ( 131.414 MB)  44.93%    3.21%
  

如果我的应用程序使用1GB的PrivateMemorySize和20GB的VirtualMemorySize,我应该关心还是可以忽略它?

在不知道您的流程将要做什么的情况下,您无法说出这一点。您可能使用了过度使用内存的第三部分DLL,例如用于数据分析。没关系。

通常,您应该对产品有一种“感觉”。如果行为发生很大变化,那么我将开始调查。

  

为什么64位版本的程序分配了更多的VirtualMemory?

可能是因为.NET不必担心其他事情。

。在32位上,只有4 GB的内存,.NET需要确保可以加载其他DLL,可以创建线程等。在64位上,如果有8 TB的内存,将永远剩下1 MB创建一个新线程。

答案 2 :(得分:0)

您提供的链接解释了这个问题:

PrivateMemorySize:

  

此属性返回的值表示进程使用的当前内存大小,该内存无法与其他进程共享。

VirtualMemorySize:

  

此属性返回的值表示进程使用的当前虚拟内存大小。操作系统将每个进程的虚拟地址空间映射到物理内存中加载的页面,或映射到磁盘上虚拟内存页面文件中存储的页面。

所以第一个通过自己的内存分配告诉应用程序消耗了多少内存,后者告诉它有多少内存映射到它(意味着使用的整个内存空间,包括PrivateMemorySize),包括操作系统和.NET框架库。