可以跨进程共享Mono虚拟机吗?

时间:2018-11-01 21:26:46

标签: c# mono

如果我想在Linux上的mono下运行两个或多个控制台应用程序,我会为每个进程带来Mono虚拟机的开销吗?还是会在进程之间重用虚拟机的某些部分?如果不是这种情况,是否可以共享单虚拟机使用的部分内存?

我想实现以下目标:假设当应用程序加载标准库的许多程序集时,单虚拟机需要100MB。应用程序A的细节使其使用额外的50Mb RAM(因此,进程A使用的总RAM为150Mb),而应用程序B的细节使它使用额外的120Mb RAM(因此,进程B使用的总RAM为220Mb)。 )。

如果Mono的工作方式,将产生两个独立的Mono虚拟机,那么我将使用370Mb的RAM。但是,如果在虚拟机之间共享基本库之类的内存,那么我只会使用100 + 50 + 120 = 270Mb的RAM。

问题是,我可能处于运行数十个或数百个相对较小的应用程序的情况,并且我担心每个单虚拟机保留的内存会极大地降低部署的内存占用量,而RAM每个单独应用程序的需求实际上并不会那么大。我说的是控制台应用程序(Web服务)。

谢谢

1 个答案:

答案 0 :(得分:1)

一如既往,取决于。 ;-)

  1. Linux将始终共享运行多次的相同可执行文件的只读段。即VM的可执行代码和常量数据在内存中仅存在一次,而可变数据未共享。

  2. 但是有一件事要知道。由于Mono是即时编译器,因此它将IL语言转换为平台的本机代码。从这里开始您的问题。 翻译后的代码在运行时生成,并且驻留在非只读内存段中。内核不再了解这种冗余,因此用于Mono类库的内存将不会在运行中的Mono VM之间共享。在同一主机上。
    (实际上,内存页面不会完全匹配,因为不同的VM可能运行的代码路径略有不同,例如,以不同的顺序或类似的方式加载运行时的类。)

  3. 如果这是故事的结尾,那么事情就很容易了,但事实并非如此。 Mono的另一个功能是: AOT(提前编译)
    在这种情况下,运行时JIT不会将ode编译为机器语言。相反,早已进行了预编译。在这种情况下,从VM实例的角度来看,预编译的代码为只读。现在,内核将再次共享预编译的代码作为常量数据。
    参见AOT: Increased Memory Sharing

  4. 但这还不是故事的结局。 AOT编译器确实支持Mono的所有功能,但具有局限性。它不能处理所有程序模式。因此,一些运行时类不共享。详细信息取决于Mono版本以及您的平台。
    有关更多详细信息,请参见Ahead of Time Compilation (AOT)

因此答案并非那么简单。取决于Mono版本以及所引用的库是否包含针对平台的预编译代码,并发运行的VM之间会共享更多或更少的内存。

实际上,这将介于您的悲观假设和乐观假设之间。您可以确定,即使AOT做得很好,也无法共享VM的某些数据段。例如。内部变量和类实例(例如反射类)将共享。
AOT仅覆盖IL代码,而不能覆盖仅依赖于设计时间常数的表达式和对象,例如C ++ constexpr

我不知道它如何在您的特定用例中扩展。但是,您正在谈论数百个相对较小的应用程序。小型应用程序很可能不会具有100 MB的运行时开销。至少我不再将其称为“小型应用程序”。


但是还有一个建议:不要启动数百个并行进程。即使Mono VM在内存共享方面做得很好,也过度使用了系统资源。请使用队列将任务委托给 limited 个进程,或者以其他方式重新考虑您的概念。否则很可能会遇到非线性可伸缩性,并且会带来糟糕的最坏情况下的性能。