程序员面试必考题(21)-Java虚拟机、垃圾收集及代码安全

微信公众号:开点工作室(ID:kaidiancs)

Java语言在最初开发时有明确的目标,这些也正是它区别于其他语言的独特之处,这些目标包括:


(1)创建一种面向对象的语言。面向对象的程序设计方法已成为主流,Java语言的语法及程序结构正是采用了这样的设计方法。


(2)提供一种解释环境,这可以缩短系统开发的编译-连接-装载-测试周期,提高开发速度。


(3)去掉了影响代码健壮性的功能,如指针结构及程序员负责的内存释放。


(4)为程序运行多线程提供了方法。


(5)允许程序下载代码模块,这样在程序运行生命期内可以动态修改它们。


(6)检查下载的代码模块,提供了保证安全的一种手段。


而Java虚拟机、垃圾收集机制及三级代码安全检查机制,使得Java得以实现这个目标。


  1. Java虚拟机


Java 虚拟机( Java virtual machine JVM )是运行 Java 程序必不可少的机制。编译后的 Java 程序指令并不直接在硬件系统的 CPU 上执行,而是由 JVM 执行。 JVM 是编译后的 Java 程序和硬件系统之间的接口,程序员可以把 JVM 看作一个虚拟的处理器。它不仅解释执行编译后的 Java 指令,而且还进行安全检查。它是 Java 程序能在多平台间进行无缝移植的可靠保证,同时也是 Java 程序的安全检验引擎。


Java虚拟机规范中给出了JVM的定义:JVM是在一台真正的机器上用软件方式实现的一台假想机。JVM使用的代码存储在.class文件中。JVM的某些指令很像真正的CPU指令,包括算术运算、流控制和数组元素访问等。


Java虚拟机规范提供了编译所有Java代码的硬件平台。因为编译是针对假想机的,所以该规范能让Java程序独立于平台。它适用于每个具体的硬件平台,以保证能运行为JVM编译的代码。JVM不但可以用软件实现,而且可以用硬件实现。


JVM的具体实现包括:指令集(等价于CPU的指令集)、寄存器组、类文件格式、栈、垃圾收集堆、内存区。


JVM的代码格式为压缩的字节码,因而效率较高。由JVM字节码表示的程序必须保持原来的类型规定。Java主要的类型检查是在编译时由字节码校验器完成的。Java的任何解释器必须能执行符合JVM定义的类文件格式的任何类文件。

Java虚拟机规范对运行时数据区域的划分及字节码的优化并不做严格的限制,它们的实现依平台的不同而有所不同。JVM的实现叫做Java运行时系统或运行时环境(Runtime Environment),简称为运行时。Java运行时必须遵从Java虚拟机规范,这样,Java编译器生成的类文件才可被所有Java运行时系统下载。嵌入了Java运行时系统的应用程序,就可以执行Java程序了。目前有许多操作系统和浏览器都嵌入了Java运行时环境。


Java 在问世之初,因其没有完全优化,并且是解释执行,所以 Java 程序的运行效率较低。同时,有着较长发展史、已非常成熟的 C++ 语言仍在开发界扮演着主要角色,人们往往拿 C++ 的性能效率与刚诞生的 Java 相比较,这当然失之偏颇。


Java解释器经过不断的优化,字节码的执行速度已有很大提高。另外,在字节码执行之前可以先经过JIT编译器进行编译,生成针对具体平台的本机执行代码。它的执行效率可比解释执行的效率大幅度提高。现在许多厂商都提供JIT编译器,这项技术已非常成熟。由于字节码与平台无关,所以经过编译的Java仍不失跨平台的特点。


Hotspot技术是Sun公司推出的另一个有特色的技术。它提供对代码的运行时选择,为的是从根本上解决Java程序的效率问题。在程序执行时,Hotspot对每个字节码指令进行分析,根据它的执行次数,动态决定它的执行方式。比如,一段指令需要多次重复执行,则立即编译为可执行代码。如果是只执行一次的简单指令,且解释执行的效率更高,则使用解释执行的方式。有了这项技术,Java的效率问题基本上可以得到解决。


2.垃圾收集机制


许多程序设计语言允许在运行时动态分配内存。分配内存的过程因各种语言的语法不同而有所不同,但总要返回指向内存块开始地址的指针。


一旦不再需要所分配的内存(指向内存的指针超出使用范围),程序或运行时环境最好将内存释放,避免内存越界时得到意外结果。


在C和C++(及其他语言)中,由程序开发人员负责内存的释放。这是个很恼人的事情,因为程序开发人员并不总是知道内存应该在何时释放。如果不释放内存,那么当系统中没有内存可用时程序会崩溃。这些程序被称为有“内存漏洞”。

在Java中,程序员不必亲自释放内存,它提供了后台系统级线程,记录每次内存分配的情况,并统计每个内存指针的引用次数。在Java虚拟机运行时环境闲置时,垃圾收集线程将检查是否存在引用次数为0的内存指针,引用次数为0即意味着没有程序再使用这块内存;如果有这样的内存的话,则垃圾收集线程把该内存“标记”为“清除”(释放),就是要归还给系统,留待下次再分配给其他的内存申请。


在Java程序生存期内,垃圾收集将自动进行,无需用户释放内存,从而消除了内存漏洞。编制程序时,程序员可以将注意力放在更需注意的地方,不仅如此,程序的调试也更加方便。


3.代码安全


Java 语言是解释执行的,但从某种意义来讲, Java 文件是“编译”的,因为它也生成了中间语言形式的文件。经过“编译”的 Java 目标代码,称为字节码,存储在 .class 文件中。字节码是不依赖于机器硬件平台的二进制代码。


运行时,类下载器下载组成Java程序的字节码,在解释器中检查并运行它们。在某些Java运行时环境中,验证过的字节码也可以被编译为本地的机器码,并直接在硬件平台上执行。


对于Applet,因其是从其他机器上通过网络下载到本机执行的,程序中可能隐藏某些非法操作,所以在Applet运行之前,系统要对之进行严格的三级代码安全检查,即验证、分析和跟踪监测。第一级验证是在类下载时完成的,检查从哪里下载文件,是否有权限进到本机系统。然后进行第二级检查,即字节码校验,此时要分析下载的字节码是否合乎规则。如果字节码的格式不合要求,则拒绝执行。完全合乎规则的字节码才允许执行。执行的时候,安全管理器始终监测所执行的每步操作,检查其合法性。Java的安全检查可以全面提高操作系统的安全等级,经过这三级安全检查的Java程序不会受到病毒的侵害。目前很多系统在做安全检查时只做第一步,即看代码下载的权限是否合乎要求。与之相比,Java的三级安全检查机制要完备得多,它不仅进行静态检查,还要进行动态跟踪。


具体地说,在Java的不同版本中,都有不同的安全机制。在最初的JDK1.0版本中,安全模型是所谓的“沙箱”模型,从网络上下载的代码只能在一个受限的环境中运行,这个环境象个箱子一样限制了代码能访问的资源。


在后来的JDK1.1版本中,提出了“签名Applet”的的概念。有正确签名的Applet视同本地代码一样,可以使用本地的资源。没有签名的Applet还与前一版本一样,只在沙箱中运行。


在Java 2平台下,安全机制又有较大改善。它允许用户自己设定相关的安全级别。另外,对于应用程序,也采取了和Applet一样的安全策略,程序员可以根据需要对本地代码或是远程代码进行设定,以保证程序更安全高效地运行。


在Java程序环境中,重要的几个组成部分包括Java解释器、类下载器及字节码校验器。


3.1 Java解释器


Java解释器只能执行为JVM编译的代码。Java解释器有三项主要工作:

(1)下载代码--由类下载器完成。

(2)校验代码--由字节码校验器完成。

(3)运行代码--由运行时解释器完成。


3.2 类下载器


Java运行时系统区别对待来自不同源的类文件。它可能从本地文件系统中下载类文件,也可能从Internet网上使用类下载器下载类文件。运行时系统动态决定程序运行时所需的类文件,并把它们下载到内存中,将类、接口与运行时系统相连接。类下载器把本地文件系统的类名空间和网络源输入的类名空间区分开来,以增加安全性。因为内置的类总是先被检查,所以可以防止起破坏作用的应用程序的侵袭。


所有的类下载完毕后,开始确定可执行文件的内存分配。此时,指定具体的内存地址,并创建查询表。因为内存分配是在运行时进行的,并且Java解释器阻止访问可能给操作系统带来破坏的非法代码地址,从而增加了保护性。


3.3 字节码校验器


Java代码在机器上真正执行前要经过几次测试。程序通过字节码校验器检查代码的安全性,字节码校验器检测代码段的格式,并使用规则来检查非法代码段--伪造的指针、对目标的访问权限违例或是试图改变目标类型或类的代码。通过网络传送的所有类文件都要经过字节码校验器的检验。


字节码校验器要对程序中的代码进行四趟扫描。这可以保证代码将依从JVM规范,并且不破坏系统的完整性。校验器主要检查以下几项内容:


(1)类遵从JVM的类文件格式。


(2)不出现访问违例情况。


(3)代码不会引起运算栈溢出。


(4)所有运算代码的参数类型总是正确的。


(5)不会发生非法数据转换,如把整数转换为指针。


(6)对象域访问是合法的。


如果完成所有的扫描之后不返回任何错误信息,就可以保证Java 程序的安全性了。

全部评论
杭州金柚网B轮一亿RMB,全国中小企业社保代缴服务标杆,2015荣登大中华区人力资源服务机构第68位(100强中唯一一家于2014年后成立的公司)。招聘开发(java、架构师、web 前端、测开)产品经理、内容运营、SEO、设计师(ui),行政,互联网2年以上工作经验。公司地址:杭州江干区凯旋路385杭钻大厦11f(闸弄口地铁站、浙大华家池公交车站)[愉快]简历接收邮箱fulm@Joyowo.com qq:80929170 欢迎推荐或自荐[拥抱] 
点赞 回复 分享
发布于 2016-07-06 09:26

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务