什么是VM,为什么动态语言需要一个?

Pep*_*ijn 22 c python java haskell vm-implementation

因此,例如,Python和Java有VM,C和Haskell没有.(如我错了请纠正我)

考虑到线路两侧有哪些语言,我找不到原因.Java在很多方面都是静态的,而Haskell提供了许多动态功能.

Oli*_*rth 27

这与静态与动态无关.

相反,它是关于独立于底层硬件平台("构建一次,到处运行" - 理论上......)

实际上,它与语言无关.可以编写一个为JVM生成字节码的C编译器.可以编写一个生成x86机器代码的Java编译器.

  • 有人*可以*?有人*有*.C到Java字节码:[NestedVM](http://nestedvm.ibex.org/); Java到机器代码:[gcj](http://gcc.gnu.org/java/). (14认同)
  • 您不需要VM来"一次编写,随处运行".Haskell代码不需要重写以在不同平台上运行.ANSI C代码也没有.你只需要一个"编译一次,随处运行"的虚拟机. (13认同)
  • 进一步示例:clang C编译器为LLVM虚拟机生成字节码.请注意,LLVM不是Java或.NET程序员所认为的全功能VM,因为它不提供操作系统环境抽象,只提供CPU抽象. (4认同)
  • 一个真实的例子:"常规"C#编译器为CLR生成字节码,而MonoTouch编译器生成本机iOS代码. (3认同)
  • @SpoonBender:您不需要VM来防止缓冲区溢出.这可以在语言级别完成,编译器根据需要静默生成运行时检查.想想,例如阿达.但是,我同意沙盒是虚拟机的固有优势. (3认同)

yai*_*chu 19

让我们忘记一秒钟的虚拟机(我们会回到下面的那些,我保证),并从这个重要的事实开始:

C没有垃圾收集.

对于提供垃圾收集的语言,必须有某种"运行时" /运行时环境/事物来执行它.

这就是为什么Python,Java和Haskell需要"运行时",而C则不需要,可以直接编译为本机代码.

需要注意的是Psyco的是,编译Python代码的机器码Python的优化,然而,很多的机器代码由调用C-Python的运行时的功能,如PyImport_AddModule,PyImport_GetModuleDict等.

Haskell/GHC与psyco编译的Python类似.Ints被添加为简单的机器指令,但是更复杂的东西,它们分配对象等,调用运行时.

还有什么?

C没有"例外"

如果我们要向C添加异常,我们生成的机器代码将需要为每个函数和每个函数调用执行一些操作.

如果我们再添加"闭包",则会添加更多内容.

现在,我们不是在每个函数中重复使用这个样板机器代码,而是调用子程序来执行必要的操作,例如PyErr_Occurred.

所以现在,基本上每个原始源代码行映射到某些函数的调用和较小的唯一部分.

但是,只要我们在每个原始源代码行中都做了这么多东西,为什么还要为机器代码烦恼呢?

这是一个想法(顺便说一下,我们将这个想法称为"虚拟机").

让我们代表你的Python代码,例如:

def has_no_letters(text):
  return text.upper() == text.lower()
Run Code Online (Sandbox Code Playgroud)

作为内存中的数据结构,例如:

{ 'func_name': 'has_no_letters',
  'num_args': 1,
  'kwargs': [],
  'codez': [
    ('get_attr', 'tmp_a', 'arg_0', 'upper'),  # tmp_a = arg_0.upper
    ('func_call', 'tmp_b', 'tmp_a', []),  # tmp_b = tmp_a() # tmp_b = arg_0.upper()
    ('get_attr', 'tmp_c', 'arg_0', 'lower'),
    ('func_call', 'tmp_d', 'tmp_c', []),
    ('get_global', 'tmp_e', '=='),
    ('func_call', 'tmp_f', 'tmp_e', ['tmp_b', 'tmp_d']),
    ('return', 'tmp_f'),
  ]
}
Run Code Online (Sandbox Code Playgroud)

现在,让我们编写一个执行此内存数据结构的解释器.

让我们讨论一下这对直接来自文本解释器的好处,然后讨论比编译到机器代码的好处.

虚拟机优于直接来自文本解释器的好处

  • 在执行代码之前,VM系统会为您提供所有语法错误.
  • 在评估循环时,VM系统不会在每次运行时解析源代码.
    • 使VM比直接从文本解释器更快.
    • 因此,直接解释器使用长变量名称运行较慢,而使用短变量名称运行速度更快.这鼓励人们写出蹩脚的数学家风格的代码,如wt(f, d(o, e), s) <= th(i, s) + cr(a, p * d + o)

虚拟机优于编译到机器代码的好处

  • 描述程序的内存数据结构或"VM代码"可能比样板机完整的机器代码紧凑得多,后者对每个原始代码行反复执行相同的操作.这将使VM系统运行得更快,因为需要从内存中获取更少的"指令".
  • 创建VM比创建编译器到机器代码要简单得多.您现在可以在不知道任何装配/机器代码的情况下执行此操作.