Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
DLL、内存映射、基址、内存使用和.NET?_.net_Memory_Dll_Base Address - Fatal编程技术网

DLL、内存映射、基址、内存使用和.NET?

DLL、内存映射、基址、内存使用和.NET?,.net,memory,dll,base-address,.net,Memory,Dll,Base Address,在我开始真正的问题之前,让我说我可能会把这里的一些细节弄错。如果是这样的话,请逮捕我,甚至不要回答我的问题 我的问题基本上是关于DLL和.NET的。我们有一个应用程序正在使用相当多的内存,我们正试图找出如何正确地测量这一点,特别是当问题主要发生在客户端的计算机上时 我想到的一件事是,我们有一些相当大的.NET程序集,其中包含生成的ORM代码 如果我使用的是具有唯一基址的非托管(Win32)DLL,那么同一台计算机上的多个并发进程将一次性将DLL加载到物理内存中,并将其映射到所有应用程序的虚拟内存

在我开始真正的问题之前,让我说我可能会把这里的一些细节弄错。如果是这样的话,请逮捕我,甚至不要回答我的问题

我的问题基本上是关于DLL和.NET的。我们有一个应用程序正在使用相当多的内存,我们正试图找出如何正确地测量这一点,特别是当问题主要发生在客户端的计算机上时

我想到的一件事是,我们有一些相当大的.NET程序集,其中包含生成的ORM代码

如果我使用的是具有唯一基址的非托管(Win32)DLL,那么同一台计算机上的多个并发进程将一次性将DLL加载到物理内存中,并将其映射到所有应用程序的虚拟内存中。因此,此DLL只使用一次物理内存

问题是.NET程序集会发生什么情况。这个DLL包含IL,虽然它的这一部分可能在应用程序之间共享,但是由此IL产生的JITted代码呢?它是共享的吗?如果不是,我该如何衡量,以找出这实际上是促成问题还是没有?(是的,我知道,这会有所帮助,但在这成为最大的问题之前,我不会在这方面花费太多时间)

另外,我知道我们还没有查看解决方案中所有.NET程序集的基址,是否需要.NET程序集这样做?如果有的话,有没有关于如何确定这些地址的指导方针

对这一领域的任何洞察都是最受欢迎的,即使事实证明这不是一个大问题,甚至根本不是一个问题


编辑:刚刚发现这个问题:部分回答了我的问题,但我仍然想知道JITted代码是如何影响所有这些的

从这个问题及其公认的答案来看,JITted代码被放置在一个堆上,这意味着每个进程将加载共享的二进制程序集映像,并在其自己的内存空间中生成代码的私有JITted副本

我们有什么办法来衡量这一点吗?如果这产生了大量的代码,我们必须更多地查看生成的代码,以确定是否需要对其进行调整


编辑:在此处添加了较短的问题列表:

  • 确保.NET程序集的基址是唯一且不重叠的,以避免对dll进行重定基址(该dll主要用于从中获取IL代码以进行JITting),这有什么意义吗
  • 我如何衡量JITted代码使用了多少内存来判断这是否真的是一个问题 答案是,正如我所预期的那样,JITting将生成每个进程的JITted代码副本,但对程序集重定基址实际上会在减少内存使用方面产生效果。我将不得不深入研究他提到的WinDbg+SoS工具,这是我在列表中列出的工具,但现在我怀疑我不能再推迟了:)


    编辑:我找到了一些关于该主题的链接:


    我认为您对共享程序集和DLL以及进程内存空间感到困惑

    NET和标准Win32 DLL在使用它们的不同进程之间共享代码。在.NET的情况下,这仅适用于具有相同版本签名的dll,以便同一dll的两个不同版本可以同时加载到内存中

    问题是,看起来您希望库调用所分配的内存也能被共享,这是从来没有(几乎)发生过的。当库中的一个函数分配内存时,我想ORMDLL经常会这样,内存分配在调用进程的内存空间中,每个进程都有唯一的数据实例

    因此,是的,事实上DLL代码被加载一次并在调用方之间共享,但是代码指令(以及分配)单独发生在调用进程空间中

    编辑: 好的,让我们看看JIT是如何处理.NET程序集的


    当我们谈论JIT代码时,过程相对简单。内部有一个名为virtualmethodtable的结构,它基本上包含调用期间将调用的虚拟地址。在.NET中,JIT的工作原理基本上是编辑该表,以便每个调用都重定向到JIT编译器。这样,每当我们调用一个方法时,JIT就会介入并将代码编译成实际的机器指令(因此是准时制),一旦完成,JIT就会返回到VMT,并替换调用him的旧条目,以指向生成的低级代码。这样,所有后续调用都将重定向到已编译代码(因此我们只编译一次)。因此,JIT并不是每次都被调用,所有后续调用都将重定向到相同的编译代码。对于DLL,过程可能是相同的(尽管我不能完全向您保证)。

    这是针对问题1)

    jitted代码被放置在一个特殊的堆上。您可以使用
    检查此堆!WinDbg+SoS中的eeheap
    命令。因此,每个进程都有自己的jitted代码副本。该命令还将显示代码堆的总大小

    如果您需要有关从WinDbg获取此信息的更多详细信息,请与我联系


    这是问题2)

    根据Expert.NET 2.0 IL Assembly一书,纯IL PE文件的
    .reloc
    部分只包含CLR启动存根的一个修复条目。因此,在重定基址期间,托管DLL所需的修复量相当有限

    但是,如果您列出任何给定的托管进程,您会注意到Microsoft已重新设置了其托管DLL的大部分(或全部)的基址。是否应将其视为重新评估的理由