即时编译器概念
⑴ jvm中线程本地内存是真实存在的,还是一个抽象概念
jvm内存模型:java代码是运行在Java虚拟机之上的,由Java虚拟机通过解释执行(解释器)或编译执行(即时编译器)来完成,故Java内存模型,也就是指Java虚拟机的运行时内存模型。
运行时内存模型,分为线程私有和共享数据区两大类,其中线程私有的数据区包含程序计数器、虚拟机栈、本地方法区,所有线程共享的数据区包含Java堆、方法区,在方法区内有一个常量池。java运行时的内存模型图,如下:
从图中,可知内存分为线程私有和共享两大类:
(1)线程私有区,包含以下3类:
程序计数器,记录正在执行的虚拟机字节码的地址;
虚拟机栈:方法执行的内存区,每个方法执行时会在虚拟机栈中创建栈帧;
本地方法栈:虚拟机的Native方法执行的内存区;
(2)线程共享区,包含以下2类
Java堆:对象分配内存的区域;
方法区:存放类信息、常量、静态变量、编译器编译后的代码等数据;
常量池:存放编译器生成的各种字面量和符号引用,是方法区的一部分。
楼主提到的Java栈,一般而言是指图中的虚拟机栈,在代码中的方法调用过程中,往往需要从一个方法跳转到另一个方法,执行完再返回,那么在跳转之前需要在当前方法的基本信息压入栈中保存再跳转。
三、关于寄存器的问题
对于java最常用的虚拟机,sun公司提供的hotspot虚拟机,是基于栈的虚拟机;而对于android的虚拟机,则采用google提供的dalvik,art两种虚拟机,在android 5.0以后便默认采用art虚拟机,这是基于寄存器的虚拟机。 楼主问的是jvm(即java vm),这是基于栈的虚拟机。那么关于虚拟机栈,这块内存的内容,我们再进一步详细分析,如下图:
可以看到,在虚拟机栈有一帧帧的 栈帧组成,而栈帧包含局部变量表,操作栈等子项,那么线程在运行的时候,代码在运行时,是通过程序计数器不断执行下一条指令。真正指令运算等操作时通过控制操作栈的操作数入栈和出栈,将操作数在局部变量表和操作栈之间转移。
⑵ java 静态变量和静态常量
静态变量是属于静态存储方式,但是属于静态存储方式的量不一定就是静态变量,例如外部变量虽属于静态存储巧配搭方式,但不一定是静态变量,必须由static加以定义后才能成为静态外部变量,或称静态全局变量。
对于自动变量,它属于动态存储方式。但是也可以用static定义它为静态自动变量,或称静态局部变量,从而成为静态存储方式。由此看来,一个变量可由static进行再说明,并改变其原有的存储方式。
而在以Pascal为代表的许多程序语言中,所有局部变量都由系统自动分配存储空间,而所有全局变量的存储空间则以静态分配的方式获取,因此由于实际上“局部变量”和“全局变量”这两个术语已足以涵盖所有的情况,在这些程序语言中通常不使用“静态变量”这一术语,而直接以“全局变量”代之。
在这些程序语言中,静态变量就是全局变量,而即使在有明确区分全局和静态变量的程序语言中,在编译后的代码里二者也以相同的方式获取存储空间。而今术语“静态变量”的概念则主要基于C族语言的“static”的定义。
静态变量也可以用于存储常数。具体来说,静态变量可用const,constant或final等关键卖卜字标识,这时其值就会在编译时设定,并且无法在运行时改变。编译器通常将静态常量与孝拿文本一起置于目标文件的文本区域,而非常量初始化数据则置于数据区
⑶ Java的核心技术有哪些
第一:Java虚拟机 Java虚拟机的主要任务是装在class文件并且执行其中的字节码。Java虚拟机包含一个类装载器,它可以从程序和API中装载class文件。Java API中只有程序执行时需要的那些类才会被装载。字节码由执行引擎来执行。不同的Java虚拟机中,执行引擎可能实现得非常不同。在由软件实现的虚拟机中,最简单的执行引擎就是一次性解释字节码。另一种执行引擎更快,但是也更消耗内存,叫做"即时编译器(just-in-time compiler)"。在这种情况下,第一次被执行的字节码会被编译成本地机器代码。编译出的本地机器代码会被缓存,当方法以后被调用的时候可以重用。第三种执行引擎是自适应优化器。在这种方法里,虚拟机开始的时候解释字节码,但是会监视运行中程序的活动,并且记录下使用最频繁的代码段。程序运行的时候,虚拟机只把那些活动最频繁的代码编译成本地代码,其他的代码由于使用得不是很频繁,继续保留为字节码-由虚拟机继续解释它们。一个自适应的优化器可以使得Java虚拟机在80%~90%的时间里执行被优化过的本地代码,而只需要编译10%~20%的对性能有影响的代码。 当Java虚拟机是由主机操作系统上的软件实现的时候,Java程序通过调用本地方法(native method)和主机交互。Java中有两种方法: Java方法和本地方法。Java方法是由Java语言编写,编译成字节码文件,存储在class文件中的。本地方法是由其他语言(比如c,c++或汇编语言)编写的,编译成何处理器相关的机器代码。本地方法保存在动态链接库中,格式是各个平台专有的。运行中Java程序调用本地方法时,虚拟机装载包含这个本地方法的动态库,并调用这个方法。本地方法是联系Java程序和底层主机操作系统的连接方法。
第二:类装载器的体系结构 一个Java应用程序可以使用两种类装载器:"启动(bootstrap)"类装载器和用户定义的类装载器。启动类装载器(这是系统中唯一的)是Java虚拟机实现的一部分。启动类装载器通常使用某种默认方式从本地磁盘中装载类,包括Java API类(启动类装载器也被称为原始类装载器、系统类装载器或者默认类装载器)。 Java应用程序能够在运行时安装用户定义的类装载器,这种类装载器能够使用自定义的方式来装载类。例如,从网络下载class文件。尽管启动类装载器是虚拟机实现的本质部分,而用户定义的类装载器不是,但用户定义的类装载器能够用Java来编写,能够被编译成class文件,能够被虚拟机装载,还能够像其它对象一样实例化。 由于有用户定义类装载器,所以不必再编译的时候就知道运行中的Java应用程序中最终会加入的所有的类。用户定义的类装载器使得在运行扩展Java应用程序成为可能。当它运行时,应用程序能够解决它需要哪些额外的类,能够决定是使用一个或是更多的用户定义的类装载器来装载。由于类装载器是用Java编写的,所以用任何在Java代码中可以表述的风格来进行类装载。这些类可以通过网络下载,可以从某些数据库中获取,甚至可以动态生成。 每一个类被装载的时候,Java虚拟机都监视这个类,看到它到底是被启动类装载器还是被用户定义类装载器装载。当被装载的类引用了另外一个类时,虚拟机就会使用装载第一个类的类装载器装载引用的类。例如,如果虚拟机使用一个特定的类装载器装载Volcano这个类,它就会使用这个类装载器装载Volcano类使用的所有类。 由于Java虚拟机采取这种方式进行类的装载,所以被装载的类默认情况下只能看到被同一个类装载器装载的别的类。通过这种方法,Java的体系结构允许在一个Java应用程序中建立多个命名空间。运行时的Java程序中的每一个类装载器都有自己的命名空间。 Java应用程序可以创建多少个(或多少种)被不同的类装载器装载的类存放在不同的命名空间中,它们不能相互访问,除非应用程序显示地允许这么做。当编写一个Java应用程序的时候,从不同源文件装载的类可以分隔在不同的命名空间中。通过这种方法,就能够使用Java类装载器的体系结构来控制任何不同源文件中装载的代码之间的相互影响,特别是能够阻止恶意代码获取访问或破坏善意代码的权限。 Web浏览器是一个动态扩展的例子,Web浏览器使用用户定义的类装载器从网络下载用于Java applet的class文件。Web浏览器使用一个用来安装用户定义类装载器的Java应用程序。这个用户定义的类装载器通常被称为Java Applet类装载器,它知道如何向HTTP服务器请求class文件。Java Applet可以作为动态扩展的例子,因为Java应用程序并不知道它什么时候会开始从网络下载浏览器请求的class文件。只有当浏览器遇到有Java applet的页面时,才决定是否需要下载class文件。 Web浏览器启动的Java应用程序通常为每个提供class文件的网络地址分别创建不同的用户定义类装载器,因此,不同的用户定义类装载器装载不同来源的class文件。这就可以把它们分别放置在Java主机应用程序的不同命名空间之下。由于不同来源的Java applet文件放置在不同的命名空间中,恶意的Java applet代码就不会直接访问从别的地方下载的class文件。这就能够限制或阻止不同来源的代码之间的相互访问。
第三:Java class文件 Java class文件主要在平台无关性和网络移动性方面使Java更适合网络。它在平台无关性方面的任务是:为Java程序提供独立于底层主机平台的二进制形式的服务。这种途径途径打破了C或者C++等语言所遵循的传统,使用这些传统语言写的程序通常首先被编译,然后被连接成单独的、专门支持特定硬件平台和操作系统的二进制文件。通常情况下,一个平台上的二进制可执行文件不能在其他平台上工作。而Java class文件时可以运行在任何支持Java虚拟机的硬件平台和操作系统上的二进制文件。 当编译和连接一个C++程序时,所获得的可执行二进制文件只能在指定的硬件平台和操作系统上运行,因为这个二进制文件包含了对目标处理器的机器语言。而Java编译器把Java源文件的指令翻译成字节码,这种字节码就是Java虚拟机的"机器语言"。class文件设计得紧凑,因此它们可以快速地在网络上传送。其次,由于Java程序是动态连接和动态扩展的,class文件可以在需要的时候才下载。这个特点使得Java应用程序能够安排从网络上下载class文件的时间,从而可以最大限度地减少终端用户的等待时间。
第四:Java API Java API通过支持平台无关性和安全性,使得Java适应于网络应用。Java API是运行库的集合,它提供了一套访问主机系统资源的标准方法。运行Java程序时,虚拟机装载程序的class文件所使用的Java API class文件。所有被装载的class文件(包括从应用程序中和从Java API中提取的)和所有已经装载的动态库(包含本地方法)共同组成了再Java虚拟机上运行的整个程序。 在一个平台能偶支持Java程序以前,必须在这个特定平台上明确地实现API的功能。为访问主机上的本地资源,Java API调用了本地方法。由于Java API class文件调用了本地方法,Java程序就不需要再调用它们了。通过这种方法,Java API class文件为底层主机提供了具有平台无关性、标准接口的Java程序。对Java程序而言,无论平台内部如何,Java API都会有同样的表现和可预测的行为。正是由于在每个特定的主机平台上明确地实现了Java虚拟机和Java API,因此,Java程序自身就能够成为具有平台无关性的程序。 Java API在Java安全性模型方面也有贡献。当Java API的方法进行任何有潜在危险的操作(比如进行本地磁盘写操作)之前,都会通过查询访问控制器来检验是否得到了授权。访问控制器是一个类,该类用来执行栈检验,已决定是否允许某种操作。
⑷ 什么叫源文件
在开发软件的过程中,我们需要将编写好的代码(Code)保存到一个文件中,这样代码才不会丢失,才能够被编译器找到,才能最终变成可执行文件。这种用来保存代码的文件就叫做源文件(Source File)。
我们将在《编译和链接》一节中讲解编译器的概念。
每种编程语言的源文件都有特定的后缀,以方便被编译器识别,被程序员理解。源文件后缀大都根据编程语言本身的名字来命名,例如:
C语言源文件的后缀是.c;
C++语言(C Plus Plus)源文件的后缀是.cpp;
Java 源文件的后缀是.java;
Python 源文件的后缀是.py;
JavaScript 源文件后置是.js。
源文件其实就是纯文本文件,它的内部并没有特殊格式,能证明这一结论的典型例子是:在 Windows 下用记事本程序新建一个文本文档,并命名为demo.txt,输入一段C语言代码并保存,然后将该文件强制重命名为demo.c(后缀从.txt变成了.c),发现编译器依然能够正确识别其中的C语言代码,并顺利生成可执行文件。
源文件的后缀仅仅是为了表明该文件中保存的是某种语言的代码(例如.c文件中保存的是C语言代码),这样程序员更加容易区分,编译器也更加容易识别,它并不会导致该文件的内部格式发生改变。
C++ 是站在C语言的肩膀上发展起来的,是在C语言的基础上进行的扩展,C++ 包含了C语言的全部内容(请猛击《C语言和C++到底有什么关系》一文了解更多),将C语言代码放在.cpp文件中不会有错,很多初学者都是这么做的,很多大学老师也是这么教的。但是,我还是强烈建议将C语言代码放在.c文件中,这样能够更加严格地遵循C语言的语法,也能够更加清晰地了解C语言和C++的区别
⑸ C++编译器即时编译问题。
断点中断后所在的行是尚未运行准备运行的行,你可以按F10单步运行过去之后,就看到结果了。
if(ia[x++]<ia[x])
这句中由于 ++ 在后,所以判断运算先进行,然后再增一,这种前后书写有关系只有在多重运算下才会生效,单独的 x++ 和 ++x 没有区别。
⑹ Python编译器推荐
1、CPython
是Python语言规范的参考实现,能够优先获得Python语言的最新、最强的功能,CPython是由C语言编写而成,不但可以从Python代码中调用C代码的函数,还可以直接在Python中使用大量现有的C代码库。
2、Brython
Brython可用于在浏览器中运行包含了Python 3脚本的Web应用。
3、PyPy Python
虽然第一个推荐的是在Python中使用最广泛的编译器,但却不是最快的,PyPy采用的是即时的编译概念,在代码执行前,就直接编译为机器代码,因此其执行速度提高了近4倍。
4、Jython或JPython
使用率第二高,Jython最初被称为JPython,是通过Python语言来实现Java虚拟机的,开发者既可以将现有的Java包和代码库,导入自己的Python程序中,还可以在Java程序中嵌入Python脚本。
5、Cython
Cython与CPython不同,更像是一个超集,允许开发者在代码中结合C和Python,从而生成C语言代码类型的输出,以供任何一种C/C++编译器进行后续编译。
6、Skulpt
流行的速度非常快,主要目的是提供一种良好的在线式Python编译器,也可以通过让Web应用引擎包含Skulpt,以方便开发者编写出被用于前端的Python脚本。
7、PyJS
是另一款完全用Python去开发Web应用的编译工具,在后台,PyJS会在使用内置的Ajax框架之前,将Python代码编译为JavaScript。
8、WinPython
是Python的"即用型"发行版,也就意味着用户无需安装,即可在Windows
PC上运行,作为另一种Python的实现,WinPython编译器不仅带来了Python执行环境,而且还包含了诸如:Scipy、Numpy、以及Pandas等各种Python库。
⑺ C#JIT的概念及作用
C#编写的程序,经过编译器把编译后,源代码被转换成Microsoft中间语言(MSIL)。MSIL不是真正可执行的代码。因此,要真正执行MSIL应用程序,还必须使用“JIT编译器”,对MSIL再次编译,以得到主机处理器可以真正执行本机指令。JIT编译器以即时方式编译MSMIL代码,以便应用程序执行。
⑻ c#泛型有什么作用
关于object类型:
1.object类型可以来引用任何类型的实例;
2.object类型可以存储任何类型的值;
3.可以定义object类型的参数;
4.可以把object作为返回类型。
但是--这样做有很大的问题
1.会因为程序员没有记住使用的类型而出错,造成类型不兼容;
2.值类型和引用类型的互化即装箱拆箱使系统性能下降。
C#2.0提出的泛型就是避免强制类型转换,减少装箱拆箱提高性能,减少错误。
System.Collections.Generic命名空间提供许多集合类和接口的泛型版本。
所谓泛型:
即通过参数化类型来实现在同一份代码上操作多种数据类型。泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。
C#泛型赋予了代码更强的类型安全,更好的复用,更高的效率,更清晰的约束。
C#泛型能力由CLR在运行时支持,区别于C++的编译时模板机制,和java的编译时的“搽拭法”。这使得泛型能力可以在各个支持CLR的语言之间进行无缝的互操作。
C#泛型代码在被编译为IL和元数据时,采用特殊的占位符来表示泛型类型,并用专有的IL指令支持泛型操作。而真正的泛型实例化工作以“on-demand”的方式,发生在JIT编译时。
C#泛型编译机制如下:
第一轮编译时,编译器只为Stack类型产生“泛型版”的IL代码和元数据,并不进行泛型类型的实例化,T在中间只充当占位符。
JIT编译时,当JIT编译器第一次遇到Stack时,将用int类型替换“泛型版”IL代码与元数据中的T -- 进行泛型类型的实例化。
CLR为所有类型参数为“引用类型”的泛型类型产生同一份代码,但如果类型参数为“值类型”,对每一个不同的“值类型”,CLR将为其产生一份独立的代码。
C#泛型的几个特点
如果实例化泛型类型的参数相同,那么JIT编译器会重复使用该类型,因此C#的动态泛型能力避免了C++静态模板可能导致的代码膨胀的问题。
C#泛型类型携带有丰富的元数据,因此C#的泛型类型可以应用于强大的反射技术。
C#的泛型采用“基类、接口、构造器、值类型/引用类型”的约束方式来实现对类型参数的“显示约束”,提高了类型安全的同时,也丧失了C++模板基于“签名”的隐式约束所具有的高灵活性。
C#泛型类在编译时,先生成中间代码IL,通用类型T只是一个占位符。在实例化类时,根据用户指定的数据类型代替T并由即时编译器(JIT)生成本地代码,这个本地代码中已经使用了实际的数据类型,等同于用实际类型写的类,所以不同的封闭类的本地代码是不一样的。按照这个原理,我们可以这样认为:泛型类的不同的封闭类是分别不同的数据类型。
这样泛型不仅更加灵活,也同时将代码的简便和提高到一个层次!不用再为具体不同的重载方法写具体的代码了!
C# 泛型是开发工具库中的一个无价之宝。它们可以提高性能、类型安全和质量,减少重复性的编程任务,简化总体编程模型,而这一切都是通过优雅的、可读性强的语法完成的。尽管 C# 泛型的根基是 C++ 模板,但 C# 通过提供编译时安全和支持将泛型提高到了一个新水平。C# 利用了两阶段编译、元数据以及诸如约束和一般方法之类的创新性的概念。毫无疑问,C# 的将来版本将继续发展泛型,以便添加新的功能,并且将泛型扩展到诸如数据访问或本地化之类的其他 .NET Framework 领域。
当然,C#的泛型还很多应用,现在我还只是了解了它的机制和原理,在接下来的学习中我会系统得学习泛型所支持的抽象泛型,接口泛型,结构和委托等!
具体的建议你看一下《deep in C#》这本书,上面解释的很生动,很有趣。中文翻译版的叫《深入理解C#》(第二版)。
⑼ linux中gnu的含义是什么
1.3.2 GNU知识
GNU的全称为GNU's not unix,意思是“GNU不是UNIX”,GNU计划,又称革奴计划,是由Richard Stallman在1984年公开发起的,是FSF的主要项目。前面已经提到过,这个项目的目标是建立一套完全自由的和可移植的类Unix操作系统。
GNU类Unix操作系统是由一系列应用程序、系统库和开发工具构成的软件集合,例如:Emacs 编辑软件、gcc 编译软件、bash 命令解释程序和编程语言,以及gawk (GNU’s awk) 等,并加上了用于资源分配和硬件管理的内核。
但是GNU自己的内核Hurd仍在开发中,离实用还有一定的距离。因此,这个GNU系统并没有流行起来。现在的GNU系统通常是使用Linux系统的内核、加上GNU项目贡献的一些组件,以及其他相关程序组成的,这样的组合被称为GNU/Linux操作系统。
到1991年Linux内核发布的时候,GNU项目已经完成了除系统内核之外的各种必备软件的开发。在Linus Torvalds和其他开发人员的努力下, GNU项目的部分组件又运行到了Linux内核之上,例如:GNU项目里的Emacs、gcc、bash、gawk等,至今都是Linux系统中很重要的基础软件。内容来自老男孩作者出版书籍。
⑽ 电脑编程的基础知识——编译器和连接器
我从没见过(不过应该有)任何一本C++教材有讲过何谓编译器(Compiler)及连接器(Linker)(倒是在很老的C教材中见过),现在都通过一个类似VC这样的编程环境隐藏了大量东西,将这些封装起来。在此,对它们的理解是非常重要的,本系列后面将大量运用到这两个词汇,其决定了能否理解如声明、定义、外部变量、头文件等非常重要的关键。
前面已经说明了电脑编程就是一个“翻译”过程,要把用户的程序翻译成CPU指令,其实也就是机器代码。所谓的机器代码就是用CPU指令书写的程序,被称作低级语言。而程序员的工作就是编写出机器代码。由于机器代码完全是一些数字组成(CPU感知的一切都是数字,即使是指令,也只是1代表加法、2代表减法这一类的数字和工作的映射),人要记住1是代表加法、2是代表减法将比较困难,并且还要记住第3块内存中放的是圆周率,而第4块内存中放的是有效位数。所以发明了汇编语言,用一些符号表示加法而不再用1了,如用ADD表示加法等。
由于使用了汇编语言,人更容易记住了,但是电脑无法理解(其只知道1是加颂隐法,不知道ADD是加法,因为电脑只能看见数字),所以必须有个东西将汇编代码翻译成机器代码,也就是所谓的编译器。即编译器是将一种语言翻译成另一种语言的程序。即使使用了汇编语言,但由于其几乎只是将CPU指令中的数字映射成符号以帮助记忆而已,还是使用的空迹电脑的思考方式进行思考的,不够接近人类的思考习惯,故而出现了纷繁复杂的各种电脑编程语言,如:PASCAL、BASIC、C等,其被称作高级语言,因为比较接近人的思考模式(尤其C++的类的概念的推出),而汇编语言则被称作低级语言(C曾被称作高级的低级语言),因为它们不是很符合人类的思考模式,人类书野亏厅写起来比较困难。由于CPU同样不认识这些PASCAL、BASIC等语言定义的符号,所以也同样必须有一个编译器把这些语言编写的代码转成机器代码。对于这里将要讲到的C++语言,则是C++语言编译器(以后的编译器均指C++语言编译器)。
因此,这里所谓的编译器就是将我们书写的C++源代码转换成机器代码。由于编译器执行一个转换过程,所以其可以对我们编写的代码进行一些优化,也就是说其相当于是一个CPU指令程序员,将我们提供的程序翻译成机器代码,不过它的工作要简单一些了,因为从人类的思考方式转成电脑的思考方式这一过程已经由程序员完成了,而编译器只是进行翻译罢了(最多进行一些优化)。
还有一种编译器被称作翻译器(Translator),其和编译器的区别就是其是动态的而编译器是静态的。如前面的BASIC的编译器在早期版本就被称为翻译器,因为其是在运行时期即时进行翻译工作的,而不像编译器一次性将所有代码翻成机器代码。对于这里的“动态”、“静态”和“运行时期”等名词,不用刻意去理解它,随着后续文章的阅读就会了解了。
编译器把编译后(即翻译好的)的代码以一定格式(对于VC,就是COFF通用对象文件格式,扩展名为.obj)存放在文件中,然后再由连接器将编译好的机器代码按一定格式在Windows操作系统下就是Portable Executable File Format--PE文件格式)存储在文件中,以便以后操作系统执行程序时能按照那个格式找到应该执行的第一条指令或其他东西,如资源等。至于为什么中间还要加一个连接器以及其它细节,在后续文章中将会进一步说明。