精华内容
下载资源
问答
  • 您可以使用Java,Python,C#,Node.js,Php,C \ C ++,Rust等任何编程语言编写rpc http客户端。 查看 部署模型 两种部署模式:网关和代理。 闸道 您可以将其部署为网关模型。 网关在独立的服务器上运行。 ...
  • 编程语言

    2020-10-18 16:23:02
    编程语言可能是编译的或是解释的,也可能是通过虚拟机执行的。许多语言都将“性能优化”作为一个特性,但是严格来讲,这个特性是执行该语言的特性,而不是语言的本身。比如,Java HotSpot虚拟机软件就是用所包含的...

    编程语言可能是编译的或是解释的,也有可能是通过虚拟机执行的。许多语言都将“性能优化”作为一个特性,但是严格来讲,这个特性是执行该语言的特性,而不是语言的本身。比如,Java HotSpot虚拟机软件就是用所包含的JIT编译器来动态提高性能的。

    编译语言:编译在运行之前将程序生成机器指令,保存在二进制可执行文件里。这些文件可以在任何时间运行,无需再编译。编译语言C/C++,还有些语言既有解释器也有编译器。编译过的代码总体来说是高性能的,在被CPU执行之前不需要进一步转换。

    解释语言:解释语言程序的执行时将语言在运行时翻译成行为,这一过程会增加执行的开销。解释语言并不期待能表现出很高的性能。而是用于其他因素更重要的情况下,诸如易于编程和调试。shell脚本就是解释语言的一个例子。

    虚拟机:或者称为进程虚拟机是模拟计算机的软件。比如java和erlang,都是用虚拟机执行,提供了平台独立的编程环境。应用程序先编译成虚拟机指令集,再由虚拟机执行。这样编译的对象具有了可移植性,只要有虚拟机就能在目标平台上运行这些程序。

    展开全文
  • PHP、Java、Python、C、C++ 这几种编程语言都什么优点或特点?(五) C++编译器的准则与virtual机制? 首先,C++的编译准则,希望做到与C一样的效率。希望做到以下: ——a) 没有运行时调用间接性。任何数据在...

    PHP、Java、Python、C、C++ 这几种编程语言都各有什么优点或特点?(五)

    C++编译器的准则与virtual机制?

    1. 首先,C++的编译准则,希望做到与C一样的效率。希望做到以下:
      ——a) 没有运行时调用间接性。任何数据在运行时都是一个地址直接就访问到。
      ——b) 没有运行时的Meta-Data。无需通过Meta-Data来访问某个复杂的类层次。
      ——c) 所有的数据都希望用C中struct来实现,即在编译时就确定好对象及其成员地址。
    2. 以上,在过程式范式,与ADT范式中都是成立的。
    3. 但是,在面向对象范式中,渴望做到:

    需要维系着同一个继承体系成员结构的一致性,只有这样,才能保证运行时的多态性。即希望通过同一个入口,访问到父类或者子类的相同数据成员、函数成员,而不在乎具体对象的是父类还是子类。

    在这里插入图片描述

    C++的virtual机制如何实现的?
    a) 虚函数
    i. 虚函数,运行时,每个有虚函数的类型(哪怕是子类)都维持着一个虚函数表,这已经是运行时的Meta-Data,通过查表,即可找到对象自己的虚函数。
    ii. 例如clone肯定是object.__vptr__Base->#3(),无论具体的对象。
    b) 多重继承
    ——如何处理后继的base基类?由编译器判断指针类型并加上相应的偏移。
    c) 虚继承
    ——添加一个虚基类指针,指向共享部分。

    这样的缺点有两个:

    1. 虚基类的子类都要背负一个基类指针指向共享部分。如果继承了多个虚基类,还需要多个这样的指针。(Microsoft的解决方法是增加一个虚基类表,类似于虚函数表。)
    2. 虚继承链条的增加,会导致间接访问的层次增加。例如两个菱形继承的串联。

    推荐观看:笨办法学Python!编程小白的第一本Python入门书!

    注意!
    点击此群,一起交流学习
    群号:Python编程资源裙
    610380249

    申请即送:Python软件安装包,Python源码,Python100道经典练习题。
    在这里插入图片描述

    展开全文
  • 不会有任何错误,并且语言运行速度将比机器代码快。 Setonas的第一个版本是3.4.6版本,该版本于2017年4月1日发布。 人们相信,从这一刻起,世界将生活在一个新的日历上- 在Setonas出现之前和之后Setonas出现。...
  • TypeScript是一个开源的编程语言,通过在JavaScript(世界上最常用的语言之一)的基础上添加静态类型定义生成。类型提供了一种描述对象形状的方法。可以帮助提供更好的文档,还可以让TypeScript验证你的代码可以正常...
  • Crystal会进行静态类型检查,因此任何类型错误将由编译器及早捕获,而不是在运行时失败。 此外,为了保持语言的整洁,Crystal具有内置的类型推断,因此不需要大多数类型注释。 在Crystal中,所有类型是非...
  • :比其他任何R运行时都更快执行R语言脚本,并且与Rcpp一样快 :与GraalVM生态系统中的其他语言快速的。 :与参考R实现(包括 :允许使用R嵌入API或用于Java的GraalVM多语言嵌入SDK进行集成 下面的屏幕快照显示了...
  • 选择JavaScript作为一种实现语言是因为它对许多程序员很熟悉并且具有一流的功能。 尝试确定 运行OK的最简单方法是使用 。 此REPL具有一些特殊的命令,可以在行的开头发出这些命令: \\ (在输入多行表达式)...
  • (1)运行Java程序就会启动对应的线程,每一个线程,都有一个寄存器,用来记录程序在当前线程执行的位置。当线程阻塞后然后再重新运行,就可以在寄存器记录的位置继续执行了。 (2)线程之间的寄存器互不影响,所以称为...

    Java在内存分配时涉及区域

    寄存器
    (1)运行Java程序就会启动对应的线程,每一个线程,都有一个寄存器,用来记录程序在当前线程执行的位置。当线程阻塞后然后再重新运行,就可以在寄存器记录的位置继续执行了。

    (2)线程之间的寄存器互不影响,所以称为线程私有的。同时,寄存器是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。在程序中无法通过代码控制寄存器的。


    (1) 每个线程包含一个栈区,栈中只保存基本数据类型的对象和对象的引用(不是对象),对象都存放在堆区中
    (2)每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。


    (1)存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
    (2)jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身
    (3)存放用new产生的数据

    方法区
    方法区是系统分配的一个内存逻辑区域,是JVM在装载类文件时,用于存储类型信息的(类的描述信息)。

    (1)Class的基本信息

    a.每个类的全限定名b.该类是类还是接口c.该类型的访问修饰符等

    (2)已装载的Class的详细信息

    a. 运行时常量池:在方法区中,每个类型都对应一个常量池,存放该类型所用到的所有常量,常量池中存储了诸如文字字符串、final变量值、类名和方法名常量。初中语文辅导它们以数组形式通过索引被访问,是外部调用与类联系及类型对象化的桥梁。(存的可能是个普通的字符串,然后经过常量池解析,则变成指向某个类的引用)

    b.字段信息:字段信息存放类中声明的每一个字段的信息,包括字段的名、类型、修饰符。字段名称指的是类或接口的实例变量或类变量,字段的描述符是一个指示字段的类型的字符串,如private A a=null;则a为字段名,A为描述符,private为修饰符

    c.方法信息:类中声明的每一个方法的信息,包括方法名、返回值类型、参数类型、修饰符、异常、方法的字节码。(在编译的时候,就已经将方法的局部变量、操作数栈大小等确定并存放在字节码中,在装载的时候,随着类一起装入方法区。)

    静态变量(静态区):

    类变量,类的所有实例都共享,我们只需知道,在方法区有个静态区,静态区专门存放静态变量和静态块。

    非RAM存储

    硬盘等永久存储空间

    西安西科软件IT培训,教育引领未来,迄今为止,已有超过10000+学子取得显著的成就,获得社会各界的一致好评。2019,你只差一个正确的选择。

    展开全文
  • 因为这些教材假定读者已经掌握了高级编程语言以及基本的计算机系统知识。 为什么选用汇编语言? 汇编语言具有若干的特色,使得在某此情况下,汇编语言是一种很好的选择。 1 快速 汇编语言程序运行的速度比...
  • 作为一种编程语言的虚拟机,实际上不只是专用于Java语言,只要生成的编译文件匹配JVM对加载编译文件的格式要求,任何语言都可以由JVM编译运行。比如 kotlin、scala等。JVM很多,不只是Hotspot,还有Jrockit、J9...

    上一篇文章我们介绍了类加载子系统,在类的加载阶段的第(2),(3)步可以发现有运行时数据,堆,方法区等名词

    • (2):将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
    • (3):在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口

    说白了运行时数据区就是类文件被类装载器装载进来之后,类中的内容(比如变量,常量,方法,对象等这些数据)得要有个去处,也就是要存储起来,存储的位置肯定是在JVM中有对应的空间

    在这里插入图片描述

    1.Method Area(方法区)

    方法区是各个线程共享的内存区域,在虚拟机启动时创建。
    在这里插入图片描述

    1.1 方法区存什么?

    方法区是用于存放 class 文件信息和运行时常量池。那 class 文件信息有什么呢?运行时常量池又是什么呢?

    1)class 文件的信息

    对于 class 简单概括一下就是类信息和静态常量池(Class Constant Pool)

    • 类信息:包括字段表和方法表,以及一些特殊方法如构造函数,接口代码等。更多内容可以参考关于字节码的这篇文章

    • class 常量池:用于存放编译时生成的各种字面量和符号引用。

      • 字面量就是我们所说的常量概念。一般包括:文本字符串(“abc")、基本数据类型的值(1)
      • 符号引用是一组符号来描述所引用的目标,因为只有在运行时才会知道每个对象的具体地址,比如 A a = new A() 并不知道A对象在运行时的内存地址。一般包括:类和接口的全限定名,字段的名称和描述符,方法的名称和描述符。(描述符是描述字段或方法的类型的字符串)

    可以理解成类信息是框架,常量池负责存储具体内容。另外,符号引用和字符串字面量的区别是,符号引用不是直接存储字符串,而是存储字符串在常量池里的索引(#~)

    2)运行时常量池

    运行时常量池也叫动态常量池,在JVM的类解析阶段,会将class常量池里的符号引用转为直接引用(内存地址)。即动态常量池是静态常量池加载到内存后的版本。

    • 与class常量池相同点:运行时常量池也是每个类都有一个的

    • 与class常量池的区别:

      • class常量池中存放的是字面量和符号引用,而运行时常量池存放的是直接引用(内存地址)

      • class常量池在编译就确定了,但运行时常量池可以动态添加内容。例如调用 String 的 intern 方法就能将 string 的值添加到 String 常量池中,这里 String 常量池是包含在动态常量池里的,但在 jdk1.8 后,将 String 常量池放到了堆中

        注:final只是将当前变量的访问标识ACC_FINAL置为1,表示当前变量值不可变(线程安全),并不能代表存储位置,更不能说有final它就进入常量池了。示例代码可以参考这篇

    PS:这里再说一下字符串常量池。在HotSpot VM里实现的string pool功能的是一个StringTable类,它是一个Hash表,默认值大小长度是1009;这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享,所以也叫全局常量池。字符串常量由一个一个字符组成,放在了StringTable上。这三个常量池的对比详细见这篇文章

    最后,一定要注意一点,静态变量现在并不是存在于方法区。在JDK7以上版本,静态变量(线程不安全)是存储于定义类型的Class对象中,而Class对象同堆中的其他对象一样都存在与GC堆中。

    1.2 永久代和元空间是什么?

    《Java虚拟机规范》只是规定了有方法区这么个概念和它的作用,,并没有规定如何去实现它。那么,在不同的JVM上方法区的实现肯定是不同的了。而我们最常听见的实现就是永久代和元空间,它们有什么关系呢?

    永久代在虚拟机当中,永久代逻辑结构上也属于堆,但是物理上不属于;而元数据区不在虚拟机当中,而是用的本地内存。JDK1.8之后,元空间(Meta Data)替代了永久代,

    • jdk1.6及以前:有永久代,常量池在方法区

    • jdk1.7:有永久代,逐步“去永久代”,常量池在堆内存

    • jdk1.8及以后:无永久代,常量池在元空间(HotSpot JVM --> JRockit JVM)

    为什么移除了永久代?参考官方解释。大概意思是移除永久代是为融合HotSpot与 JRockit而做出的努力,因为JRockit没有永久代,不需要配置永久代。

    在这里插入图片描述

    2.Heap(堆)

    Java堆是Java虚拟机所管理内存中最大的一块,在虚拟机启动时创建,被所有线程共享。 用于存放对象的实例和数组,几乎所有对象(包括常量池)都在堆上分配内存,当对象无法在该空间申请到内存是将抛出OutOfMemoryError异常。同时也是垃圾收集器管理的主要区域。

    在这里插入图片描述

    2.1 堆的组成

    堆(heap)由两部分组成,新生代(Young)和老年代(Old),而新生代又分为伊甸区(Eden)和幸存者区(Survivor),幸存者区又分为From区(S0)和To区(S1):

    • 新生代(1/3):新生对象 -> MinorGC
      • 伊甸区(Eden space 8/10):新对象一般都创建在伊甸区,经过MinorGC且存活的对象会进入幸存者区
      • 幸存者区(Survior space): From(1/10) <–GC15–> To(1/10),同一时间 From 和 To 只能一个有数据一个空
    • 老年代(2/3):大对象 + 多次GC后仍存在的对象 -> FullGC

    下面的图直观的展示了堆的组成及各部分的大小关系:

    在这里插入图片描述
    问题一:为什么需要Survivor区?只有Eden不行吗?

    如果没有 Survivor,并且没有年龄限制的话,Eden 区每进行一次 Minor GC,存活的对象就会被送到老年代。 这样一来,老年代很快被填满,从而触发 Major GC(因为Major GC一般伴随着Minor GC,随意也可以看做触发了Full GC)。

    而老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多。执行时间长有什么坏处?频发的 Full GC消耗的时间很长,会影响大型程序的执行和响应速度。

    可能你会说,那就对老年代的空间进行增加或者较少咯。

    • 假如增加老年代空间,更多存活对象才能填满老年代。虽然降低 Full GC 频率,但是随着老年代空间加大,一旦发生Full GC,执行所需要的时间更长
    • 假如减少老年代空间,虽然 Full GC 所需时间减少,但是老年代很快被存活对象填满,Full GC频率增加

    所以,Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生。Survivor的预筛选保证只有经历16 次Minor GC后,还能在新生代中存活的对象,才会被送到老年代。

    问题二:为什么需要两个Survivor区?

    我们现在知道了必须设置Survivor区,也就是说问题是为什么一个Survivor区不行?

    假设现在只有一个Survivor区,我们来模拟一下流程: 刚刚新建的对象在Eden中,一旦Eden满了,触发一次Minor GC,Eden中的存活对象就会被移动到Survivor区。这样继续循环下去,下一次Eden满了的时候问题来了。

    此时进行Minor GC,Eden和Survivor各有一些存活对象,如果此时把Eden区的存活对象硬放到Survivor区,很明显这两部分对象所占有的内存是不连续的,也就导致了内存碎片化。

    所以,两个Survivor区最大的好处就是解决了碎片化,永远有一个Survivor space是空的,另一个非空的Survivor space无碎片。

    2.2 对象应该在哪里创建?

    既然堆中有这么多区域,那一个对象的创建到底在哪个区域呢?一般情况下,新创建的对象都会被分配到Eden区,一些特殊的大的对象会直接分配到Old区。

    比如有对象A,B,C等创建在Eden区,但是Eden区的内存空间肯定有限,比如有100M,假如已经使用了 100M或者达到一个设定的临界值,这时候就需要对Eden内存空间进行清理,即垃圾收集(Garbage Collect), 这样的GC我们称之为Minor GC,Minor GC指得是Young区的GC。

    经过GC之后,有些对象就会被清理掉,有些对象可能还存活着,对于存活着的对象需要将其复制到Survivor 区,然后再清空Eden区中的这些对象。 若此时只有Eden区和From中有对象,To 中是空的。 那么进行一次GC操作,From区中对象的年龄就会+1,我们知道Eden区中所有存活的对象会被复制到To 区, From区中还能存活的对象会有两个去处:

    • 若对象年龄达到之前设置好的年龄阈值,此时对象会被移动到Old区
    • 如果Eden区和From区没有达到阈值的 对象会被复制到To 区

    此时Eden区和From区已经被清空(被GC的对象肯定没了,没有被GC的对象都有了各自的去处)。 这时候From和To 交换角色,之前的From变成了To ,之前的To 变成了From。也就是说无论如何都要保证名为To 的Survivor区域是空的。 Minor GC会一直重复这样的过程,直到To 区被填满,然后会将所有对象复制到老年代中。

    若最后老年代也满了,这时候将发生Major GC(也可以叫 Full GC), 进行老年区的内存清理。若老年区执行了Full GC之后发现依然无法进行对象的保存,就会抛出 OOM(OutOfMemoryError)异常。

    下面这张图就叫做对象的一生把:
    在这里插入图片描述

    2.3 方法区和堆的关系?

    方法区中包含类的信息,堆中会有对象,那么怎么知道对象时哪个类创建的呢?所以,堆上的所有对象一定要有什么方式指向方法区。具体内容本篇就不说了,在下一篇 【JVM】堆(Heap)上有什么?对象全方位解析。。。

    3.Java Virtual Machine Stacks(虚拟机栈)

    假如,目前的阶段是初始化完成了,后续做什么呢?肯定是Use使用咯,不用的话这样折腾来折腾去有什么意义?那怎样才能被使用到?换句话说里面内容怎样才能被执行?

    比如通过主函数main调用其他方法,这种方式实际上是main线程执行之后调用的方法,即要想使用里面的各种内容,得要以线程为单位,执行相应的方法才行。

    那一个线程执行的状态如何维护?一个线程可以执行多少个方法?这样的关系怎么维护呢?

    虚拟机栈是一个线程执行的区域,保存着一个线程中方法的调用状态。换句话说,一个Java线程的运行状态,由一个虚拟机栈来保存,所以虚拟机栈肯定是线程私有的,独有的,随着线程的创建而创建(一个线程对应一个栈)。

    每个方法在执行的同时都会创建一个栈帧(用于存储局部变量表,操作数栈,动态链接,方法出口等信息)不存在垃圾回收问题,只要线程一结束该栈就释放,生命周期和线程一致。

    在这里插入图片描述

    3.1 栈帧的组成

    上面说了栈帧(一个方法就一个栈帧),那栈帧的组成是什么呢?由四部分组成:

    在这里插入图片描述

    • 局部变量表:方法中定义的局部变量以及方法的参数存放在这张表中
      • 局部变量表中的变量不可直接使用,如需要使用的话,必须通过相关指令将其加载至操作数栈中作为操作数使用
      • 所有在方法里初始化的对象,都是线程私有的,一般安全
      • 不存在垃圾回收问题,只要线程一结束就释放,生命周期与线程一致
    • 操作数栈:以压栈和出栈的方式存储操作数的
    • 动态链接:指向运行时常量池的引用(A reference to the run-time constant pool)
    • 方法出口:方法返回地址。当一个方法开始执行后,只有两种方式可以退出,一种是遇到方法返回的字节码指令;一种是遇见异常,并且 这个异常没有在方法体内得到处理

    PS:一个栈帧需要分配多少内存在程序编译期就已确定,而不会受到程序运行期变量数据的影响

    4.The pc Register(程序计数器)

    我们都知道一个JVM进程中有多个线程在执行,而线程中的内容是否能够拥有执行权,是根据 CPU调度来的。

    假如线程A正在执行到某个地方,突然失去了CPU的执行权,切换到线程B了,然后当线程A再获得CPU执行权的时候,怎么能继续执行呢?这就是需要在线程中维护一个变量,记录线程执行到的位置。

    程序计数器占用的内存空间很小,由于Java虚拟机的多线程是通过线程轮流切换,并分配处理器执行时间的方式来实现的,在任意时刻,一个处理器只会执行一条线程中的指令。因此,为了线程切换后能够恢复到正确的执行位置,每条线程需要有一个独立的程序计数器(线程私有)。

    说白了,程序计数器就是一个指针,指向方法区中的方法字节码(用来存储指向吓一跳指令的地址,也即将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计:

    • 如果线程正在执行Java方法,则计数器记录的是正在执行的虚拟机字节码指令的地址
    • 如果正在执行的是Native方法,则这个计数器为空

    5.Native Method Stacks(本地方法栈)

    和栈作用很相似,都是线程私有,区别不过是Java栈为JVM执行Java方法服务,而本地方法栈为JVM执行native方法服务。登记native 方法,在Execution Engine执行时加载本地方法库

    关于执行引擎,请看下一篇文章

    展开全文
  • 安装Visual Studio,请确保在“编程语言”类别下选择“ Visual C ++”。 如果您忘记这样做,则始终可以重新运行安装文件并修改现有安装。 正在安装 步骤1:启动Visual Studio,然后选择“文件” >“打开” >“从源...
  • JavaScript编程知识总结

    2019-02-25 10:12:33
    计算机只能识别机器语言,而我们平常遇到的编程语言一般是高级语言;计算机是不能直接识别的,所以需要编译器对高级语言进行解释成机器语言。这样计算机才能执行高级语言的指令; 解释型语言:在程序运行时进行...
  • 由于计算机的出现,算术化的倾向在近代数学中的作用日益显著,越来越为...资源占用少、速度快:汉语程序设计语言任何环境中运行只需很小的空间即可完成全部的操作,精巧的内核可以嵌入任何设备和系统,最小只有4K。
  • 协程  协程,即协作式程序,其思想是,一系列互相依赖的协程间依次使用CPU...  与线程不同,协程是自己主动让出CPU,并交付他期望的下一个协程运行,而不是在任何时候都有可能被系统调度打断。因此协程的使用更加清
  • 学习任何一门编程语言,都会从HelloWorld开始。对于一门从未接触过的语言,在短时间内我们都能...这篇文章将简单的讨论程序的运行机制每一种语言都有自己的开发平台,我们的程序大多是也都是在这里诞生的。从程序源代码
  • delphi经典编程入门

    2014-06-27 17:22:30
    窗体上栅格(Grids),供放置部件时对齐位置用,在程序运行时Grids是不可见的。 一个真正的应用程序可能不止一个窗口,您可以选用不同的窗体进行设计。其它窗体可以是对话框(Dialog Box)、数据录入框等。  1.2...
  • C语言是一种面向过程的语言,这就意味着C语言缺乏有关面向对象编程的...OC一个运行时系统。 OC非常丰富的类库。 程序的入口,一个程序且只有一个main函数 OC中常用的数据类型,前缀NS NSInteger 整型 NSUInt
  • XML高级编程

    2012-05-30 12:02:59
    但是,为了能够使用本书中提到的所有样例,你必须得一个浏览器,一个兼容ASP的Web服务器(例如Microsoft的Personal Web Server)并(作为运行Java程序的最小环境)安装Sun Java运行时环境(JRE)。
  • c#语言基础

    2011-12-20 23:19:16
    任何遵守通用语言规范的语言源程序, 可编译为相同的中间语言代 码,由 CLR 负责执行。只要为其它操作系统编制相应的 CLR,中间语言代码也可在其 它系统中运行。 自动内存管理:CLR 内建垃圾收集器,当变量实例的...
  • IOS编程中使用多线程

    2011-08-26 15:44:05
    不管使用任何编程语言,在实现多线程时都是一件很麻烦的事情。更糟糕的是,一旦出错,这种错误通常相当糟糕。然而,幸运的是apple从os x10.5在这方面做了很多的改进,NSThread的引入,使得开发多线程应用程序容易多...
  • 本书定位LINUX环境编程入门与提高的最佳读物,全书400余幅图表,近百篇源代码,力争做到图文并茂,作为粤嵌教育的专业教员,我和我的同事...当然,学习过任何一门编程语言将使你在阅读和学习本书的内容更加稳操胜券。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 610
精华内容 244
关键字:

任何编程语言都有运行时