您现在的位置是:主页 > news > angularjs做网站/推广合作

angularjs做网站/推广合作

admin2025/5/17 23:24:04news

简介angularjs做网站,推广合作,武汉武昌做网站推广,网页浏览器的单词JVM对话录问:你说你熟悉JVM,那你讲一将JVM是什么吧 答:嗯,好的。JVM是Java Virtual Machine的首字母缩写,译为Java虚拟机。为什么会有JVM呢?在JVM之前,同一个程序,要想在不同平台的…

angularjs做网站,推广合作,武汉武昌做网站推广,网页浏览器的单词JVM对话录问:你说你熟悉JVM,那你讲一将JVM是什么吧 答:嗯,好的。JVM是Java Virtual Machine的首字母缩写,译为Java虚拟机。为什么会有JVM呢?在JVM之前,同一个程序,要想在不同平台的…

JVM对话录

问:你说你熟悉JVM,那你讲一将JVM是什么吧

答:嗯,好的。JVM是Java Virtual Machine的首字母缩写,译为Java虚拟机。为什么会有JVM呢?在JVM之前,同一个程序,要想在不同平台的机器上运行,就需要编写不同的代码,那么能不能实现只编写一套代码,就可以在所有平台上执行呢?JVM就是这个问题的解决方案之一。那么JVM怎么解决这个问题的呢?那就要搞清楚为什么不同平台需要编写不同的代码。由于不同平台的CPU指令集不同,那么其解释的执行的机器码就不同,那么怎么统一呢?设计者这里提出的方案是:完全统一是不可能的,那就尽量统一,代码是不能变的,那就只能平台变了,那平台是用户选择的,好像也不能变,那就抽取一个中间层,只需要为不同平台编写一次一个中间层做转化,那就可以了。这个中间层设计就是JVM。所以JVM是一个通过软件虚拟出来的计算机,它有自己完善的硬件架构及指令系统。类似PDF文件和PDF阅读器,对于同一份PDF文件,只要不同平台上都有PDF阅读器,都是可以打开,这里的PDF文件就等同于Class文件,PDF阅读器就等同于JVM。

问:好的,那么JVM的组成结构是什么样的呢?

答:JVM主要由类加载器【classloader】、运行时数据区【runtime data area】、执行引擎【execution engine】和本地库接口【native interface】四部分组成。其中类加载器负责加载class文件,运行时数据区负责存放class文件解析出来的数据结构,执行引擎负责执行运行时数据区中的指令,本地库接口负责调用本地接口。

问:你能细说一下类加载吗?

答:好的,类加载是一个过程,简单来说就是把编译好的class文件加载到运行时数据区的过程。一个类从加载到JVM内存中开始,到卸载出内存为止,一般要经过加载、验证、准备、解析、初始化、使用和卸载这七个阶段。其中验证、准备和解析可统称为连接,而类加载过程只包括其中的加载、连接和初始化这几个阶段。加载阶段是通过类的全限定名获取该类的二进制字节流,并将其包含的静态结构转化为运行时数据区中的结构,最后在堆中生成一个java.lang.Class类型的对象用以作为该数据的引用。验证阶段主要包括文件格式验证、元数据验证、字节码验证、引用符合验证,其中文件格式验证是与加载阶段一起发生的,用以验证该二进制字节流的格式,确定是否能够被加载;元数据验证和字节码验证则是对语法、语义验证,引用符号验证则与解析阶段一起发生。准备阶段是为类变量分配内存和数值初始化,这里的数值初始化是指为变量赋默认值而非代码定义的值,final类型的值已在编译过程就已经确定了。解析阶段则是将符号引用替换为直接引用,符号引用是指在解析之前,由于未确定一个类型中引用另一个类型,而另一个类型是否已被加载还是未知的,所以暂用一个无意义的符号替代该引用,在解析阶段时,如果确认该类型已被加载,则使用该类型的真实引用来替换。需要注意的是,解析阶段可能发生在初始化阶段之后,发生在之后称为动态解析,发生在之前称为静态解析。对于另一个类型是抽象类或者接口,则在加载了该类型之后其实还是无法获取到真实引用的,所以需要等到在使用时,也就是在虚拟机栈中动态解析。初始化阶段是执行类变量赋值和静态代码块,也就是指clinit<>()方法。

问:好的,那你知道类加载器有哪些吗?

答:关于类加载器,JVM规范其实只定义了两类:一类是启动类加载器,另一类则是非启动类加载器了。不同的JVM规范实现,具体的分类又不一样,对于常用的hotspot,是分成了四类,hotspot将非启动类加载器又细分成了扩展类加载器、应用程序类加载器和用户自定义类加载器。启动类加载器用以加载核心类库,默认是加载JAVA_HOME/lib下的指定类库,扩展类加载器用以加载扩展类库,默认加载JAVA_HOME/lib/ext下的所有类库,应用程序类加载器用以加载classpath下的所有类库,用户自定义类加载器则可以加载用户自定义路径下的类库。

问:嗯,那么类加载器之间的关系是什么样的?知道双亲委派模型吗?

答:类加载器的功能简单来说就是将class类记载到运行时数据区,理论上来说,一个类加载器就够了,为什么需要设计这么多类加载器呢?透过结果推断起因。一般来说,一个应用程序应该不止一个类,那么如果只有一个类加载器,对于核心类库,每个类都会加载一遍,为了防止必要的核心类库重复加载,因此,可以使用分层设计,引入JVM规范的两层设计,即用于加载核心类库的启动类加载器和用于加载用户扩展类库的非启动类加载器。那么这两类加载器需要有什么样的关系才能避免重复加载呢?从内到外,即先加载核心的,再加载扩展的,所以是先加载启动类加载器,再加载非启动类加载器。所以,较优解是,对于一个应用的多个类加载,启动类加载器只加载一次,其他扩展类,如果相同的话,也只加载一次就好。具体的设计模型就是:分层加载,下层类加载器先启动,收到加载请求后,先委派给上层类加载器加载,当上层类加载器无法加载时,下层类加载器再加载。这个模型就是所谓的双亲委派模型了。但是这个模型还是存在些许问题的,这个模型是在JDK2引进的,但当时已经有类加载机制了,也就是已经定义好了loadClass方法,为了符合开闭原则,尽量不修改之前版本已经定义好的方法,设计者只能引入了一个新的findClass方法来提供给开发者重构加载机制,这算是第一次破坏。再之后发现这种单向层的设计有一个问题就是,现实应用场景可能需要上层类加载器调用下层类加载器,因此设计者又引入了线程上下文类加载器【Thread-Context-Classloader】的设计,在JDK6提供java.util.ServiceLoader类以支持SPI【Service-Provider-Interface】,这算是第二次破坏。再到后来对热替换、热部署的追求,IBM主导了OSGi模块化标准,采用更复杂的树状型加载结构,形成第三次破坏。到JDK9引入了模块化,将扩展类加载器改为了平台类加载器,并移除了java.lang.URLClassLoader的继承关系,平台类加载器在收到加载请求时,会进行模块化判断,从而形成第四次破坏。

问:你刚才谈到运行时数据区,你能详细讲讲吗?

答:运行时数据区是JVM的存储区域,包括程序计数器、虚拟机栈、本地方法栈、堆和方法区五个区域,其中除了堆和方法区外是线程共享的,其他三个区域都是线程隔离的。其中,程序计数器存储的是虚拟机字节码指令的地址,该地址用来指示线程接下来该执行什么指令,如果是本地方法,则值为undefined。虚拟机栈存储的是局部变量表、操作数栈、动态链接、方法出口等信息。本地方法栈与虚拟机栈几乎是一致的,区别在于本地方法栈是本地方法的内存模型,而虚拟机栈是非本地方法的内存模型。堆存储的是数组和对象实例。方法区存放的是类的类型信息、常量、静态变量、即时编译器编译后的代码缓存等。

问:方法区、永久代和元空间有什么关系?

答:方法区是JVM规范中定义的一块内存空间,是概念模型。永久代是JVM垃圾回收中分代机制中的概念。元空间是使用本地内存实现的。
在hotspot中,早期为了让垃圾回收器也可以管理方法区,所以使用了永久代来实现方法区,但随着hotspot兼容jrockit的优秀功能,逐步采用本地内存来实现方法区。到JDK7,已经把字符串常量池、静态变量等移除了永久代,到JDK8,完全废弃了永久代的概念,采用jrockit的元空间来实现方法区。

问:你提到了垃圾回收机制,你能详细讲讲吗?

答:好的,相较于C、C++需要程序员手动来实现内存的管理,Java提供了内存动态分配和垃圾收集技术来实现自动内存管理。所谓内存动态分配是说,一个类的类型信息、常量和静态变量会被分配到方法区,数组和对象实例会被分配到堆,操作指令分配到程序计数器,基本数据类型和对象引用等则被分配到虚拟机栈或本地方法栈,而由于程序计数器、虚拟机栈和本地方法栈是线程私有的,随着线程生死,所以不必过多考虑内存回收问题,而堆和方法区是线程共享的,因此垃圾收集技术主要关注的就是堆和方法区。那么怎么判断

对于刚才提到的运行时数据区域,除了程序计数器不会出现OutOfMemoryError外,虚拟机栈和本地方法栈在线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError,在栈扩展时无法申请到足够内存时会抛出OOM,堆中没有内存完成实例分配且无法再扩展时,会抛出OOM,方法区在无法满足新的内存分配需求时,将抛出OOM。但内存总是有限制的,而内存不总是在使用的,因此要进行内存管理,第一步需要进行垃圾的识别,也就是需要知道哪些对象还存活,哪些已经死去。判断对象的死活有两种典型的算法,分别是引用计数法和可触达性分析法。引用计数法是指在对象中添加一个引用计数器,每当有一个地方引用,计数器就加一,当引用失效时,计数器就减一,任何时刻,计数器为零的对象就是不可能再被使用的。这个算法优点是原理简单,判定高效;缺点是需要配合大量额外处理很多例外情况,比如循环引用。可触达性分析法是指根据引用关系从根节点向下搜索对象形成引用链,如果某个对象到根节点之间没有任何引用链相连,则说明不可达,也就是该对象不可能在被使用。可触达性分析法的问题在于根节点的确认,一般用作根节点的是虚拟机栈和本地方法栈中引用的对象、方法区中类静态属性和常量引用的对象、JVM内部的引用、所有被同步锁持有的对象等。在判定了对象的存活状态之后,就是要解决何时回收的问题了。迄今为止,所有收集器在枚举根节点时都必须暂停用户线程,也就是stop the world。hotspot使用了OopMap的数据结构来记录对象引用,但也不是每条指令都生成OopMap,而是在