1. 《java虚拟机精讲》epub下载在线阅读全文,求百度网盘云资源
《Java虚拟机精讲》(高翔龙)电子书网盘下载免费在线阅读
链接: https://pan..com/s/1xfrNROyJsWDumjLR07cVlA
书名:Java虚拟机精讲
作者:高翔龙
豆瓣评分:7.9
出版社:电子工业出版社
出版年份:2015-5
页数:280
内容简介:
《Java虚拟机精讲》内容简介:HotSpot VM是目前市面上高性能JVM的代表作之一,它采用解释器+JIT 编译器的混合执行引擎,使得Java 程序的执行性能从此有了质的飞跃。本书以极其精练的语句诠释了 HotSpot VM的方方面面,比如:字节码的编译原理、字节码的内部组成结构、通过源码的方式剖析 HotSpot VM 的启动过程和初始化过程、Java 虚拟机的运行时内存、垃圾收集算法、垃圾收集器(重点讲解了Serial 收集器、ParNew收集器、Parallel收集器、CMS(Concurrent-Mark-Sweep)收集器和 G1(Garbage-First)收集器)、类加载机制,以及HotSpot VM 基于栈的架构模型和执行引擎(解释器的工作流程、JIT 编译器的工作流程、分层编译策略、热点探测功能)等技术。
如果你对JVM 感兴趣,并且从未接触过 JVM,那么本书将会是你探索 JVM 世界的必备入门工具。
本书适用于任何对Java 虚拟机感兴趣的Java 开发人员、系统架构师、Java 虚拟机爱好者。尤其是对于那些从未接触过Java 虚拟机的Java 开发人员,本书笔者竭尽所能用最精练和直接的语句诠释了有关Java 虚拟机的方方面面,只要你熟练掌握了Java 编程基础,那么阅读本书你将不会感觉到任何的吃力和枯燥乏味。
作者简介:
曾任平安科技高级架构师,负责高并发即时通讯系统“天下通”的系统架构设计、架构优化、核心功能研发等工作。目前就职于一家互联网创业公司,担任系统架构师,负责企业内部Hadoop大数据平台的推广和实施、系统性能调优、对新员工技术培训等工作,对系统架构设计、大数据、Java虚拟机等技术领域有着浓厚的兴趣和丰富的实战经验。
2. openjdk oracle jdk 用哪个
首先要先明确之间,以及OpenJDK 6、OpenJDK 7、OpenJDK 7u和OpenJDK 8等项目之间是什么关系,这有助于确定接下来编译要使用的JDK版本和源码分支。
从前面介绍的Java发展史中我们了解到OpenJDK是Sun在2006年末把Java开源而形成的项目,这里的“开源”是通常意义上的源码开放形式,即源码是可被复用的,例如IcedTea、UltraViolet都是从OpenJDK源码衍生出的发行版。但如果仅从“开源”字面意义(开放可阅读的源码)上看,其实Sun自JDK 1.5之后就开始以Java Research License(JRL)的形式公布过Java源码,主要用于研究人员阅读(JRL许可证的开放源码至JDK 1.6 Update 23为止)。把这些JRL许可证形式的Sun/OracleJDK源码和对应版本的OpenJDK源码进行比较,发现除了文件头的版权注释之外,其余代码基本上都是相同的,只有字体渲染部分存在一点差异,Oracle JDK采用了商业实现,而OpenJDK使用的是开源的FreeType。当然,“相同”是建立在两者共有的组件基础上的,Oracle JDK中还会存在一些Open JDK没有的、商用闭源的功能,例如从JRockit移植改造而来的Java Flight Recorder。预计以后JRockit的MissionControl移植到HotSpot之后,也会以Oracle JDK专有、闭源的形式提供。
Oracle的项目发布经理Joe Darcy在OSCON 2011上对两者关系的介绍也证实了OpenJDK 7和Oracle JDK 7在程序上是非常接近的,两者共用了大量相同的代码(如下图,注意图中提示了两者共同代码的占比要远高于图形上看到的比例),所以我们编译的OpenJDK,基本上可以认为性能、功能和执行逻辑上都和官方的Oracle JDK是一致的。
Dalvik 与java虚拟机:
1.java虚拟机基于栈。 基于栈的机器必须使用指令来载入和操作栈上数据,所需指令更多更多 .
而dalvik虚拟机是基于寄存器的:java虚拟机运行的是java字节码。
(java类会被编译成一个或多个字节码.class文件,打包到.jar文件中,java虚拟机从相应的.class文件和.jar文件中获取相应的字节码)2.Dalvik和Java之间的另外一大区别就是运行环境——Dalvik经过优化,允许在有限的内存中同时运行多个虚拟机的实例OpenJDK :
[root@localhost ~]# java -version
java version "1.6.0_39"
OpenJDK Runtime Environment (IcedTea6 1.13.11) (rhel-1.13.11.0.el5_11-x86_64)OpenJDK 64-Bit Server VM (build 23.25-b01, mixed mode)oracle jdk:
java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)OpenJDK下载:
http://openjdk.java.net/install/index.htmlJDK 8:yum install java-1.8.0-openjdk
JDK 7:
yum install java-1.7.0-openjdk
JDK 6:yum install java-1.6.0-openjdk
1. HotSpot历史
SUN的JDK版本从1.3.1开始运用HotSpot虚拟机, 2006年底开源,主要使用C++实现,JNI接口部分用C实现。
HotSpot是较新的Java虚拟机,用来代替JIT(Just in Time),可以大大提高Java运行的性能。
Java原先是把源代码编译为字节码在虚拟机执行,这样执行速度较慢。而HotSpot将常用的部分代码编译为本地(原生,native)代码,这样显着提高了性能。
HotSpot JVM 参数可以分为规则参数(standard options)和非规则参数(non-standard options)。
规则参数相对稳定,在JDK未来的版本里不会有太大的改动。
非规则参数则有因升级JDK而改动的可能。
规则和非规则参数这里不做介绍了,网上资料很多。
2.HotSpot基础知识
HotSpot包括一个解释器和两个编译器(client 和 server,二选一的),解释与编译混合执行模式,默认启动解释执行。
编译器:java源代码被编译器编译成class文件(字节码),java字节码在运行时可以被动态编译(JIT)成本地代码(前提是解释与编译混合执行模式且虚拟机不是刚启动时)。
解释器: 解释器用来解释class文件(字节码),java是解释语言(书上这么说的)。
server启动慢,占用内存多,执行效率高,适用于服务器端应用;client启动快,占用内存小,执行效率没有server快,默认情况下不进行动态编译,适用于桌面应用程序。
由-XX:+RewriteFrequentPairs参数控制 client模式默认关闭,server模式默认开启在jre安装目录下的lib/i386/jvm.cfg 文件下。
java -version
Java HotSpot(TM) Client VM (build 14.3-b01, mixed mode, sharing)mixed mode 解释与编译 混合的执行模式 默认使用这种模式java -Xint -version
Java HotSpot(TM) Client VM (build 14.3-b01, interpreted mode, sharing)interpreted 纯解释模式 禁用JIT编译
java -Xcomp -version
Java HotSpot(TM) Client VM (build 14.3-b01, compiled mode, sharing)compiled 纯编译模式(如果方法无法编译,则回退到解释模式执行无法编译的方法)3.动态编译
动态编译(compile ring run-time),英文称Dynamic compilation;Just In Time也是这个意思。
HotSpot对bytecode的编译不是在程序运行前编译的,而是在程序运行过程中编译的。
HotSpot里运行着一个监视器(Profile Monitor),用来监视程序的运行状况。
java字节码(class文件)是以解释的方式被加载到虚拟机中(默认启动时解释执行)。 程序运行过程中,那一部分运用频率大,那些对程序的性能影响重要。对程序运行效率影响大的代码,称为热点(hotspot),HotSpot会把这些热点动态地编译成机器码(native code),同时对机器码进行优化,从而提高运行效率。对那些较少运行的代码,HotSpot就不会把他们编译。
HotSpot对字节码有三层处理:不编译(字节码加载到虚拟机中时的状态。也就是当虚拟机执行的时候再编译),编译(把字节码编译成本地代码。虚拟机执行的时候已经编译好了,不要再编译了),编译并优化(不但把字节码编译成本地代码,而且还进行了优化)。
至于那些程序那些不编译,那些编译,那些优化,则是由监视器(Profile Monitor)决定。
4.为什么不静态编译那?
为什么字节码在装载到虚拟机之前就编译成本地代码那?
动态编译器也在许多方面比静态编译器优越。静态编译器通常很难准确预知程序运行过程中究竟什么部分最需要优化。
函数调用都是很浪费系统时间的,因为有许多进栈出栈操作。因此有一种优化办法,就是把原来的函数调用,通过编译器的编译,改成非函数调用,把函数代码直接嵌到调用出,变成顺序执行。
面向对象的语言支持多态,静态编译无效确定程序调用哪个方法,因为多态是在程序运行中确定调用哪个方法。
jdk 1.9 等价JDK9 J2SE9 JAVA9
jdk 1.8 等价JDK8 J2SE8 JAVA8
jdk 1.7 等价JDK7 J2SE7 JAVA7
jdk 1.6 等价JDK6 J2SE6 JAVA6
jdk 1.5 等价JDK5 J2SE5 JAVA5
jdk 1.4 等价J2SE1.4
jdk 1.3 等价J2SE1.3
jdk 1.2 等价J2SE1.2
jdk 1.1
openjdk源码下载:
Oracle JDK只发布二进制安装包,而OpenJDK只发布源码复制代码
获取OpenJDK源码有两种方式:
第一种方式:
下载OpenJDK7u的源代码:
hg clone http://hg.openjdk.java.net/jdk7u/jdk7u-devcd jdk7u-dev
chmod 755 get_source.sh
./get_source.sh
下载OpenJDK8u的源代码:
hg clone http://hg.openjdk.java.net/jdk8u/jdk8u-devcd jdk8u-dev
./get_source.sh
注意:这是最直接的方式,从版本管理中看变更轨迹比看Release Note效果更好。但不足之处是速度太慢,虽然代码总容量只有300 MB左右,但是文件数量太多,在笔者的网络下全部复制到本地需要数小时。
第二种方式,即直接下载官方打包好的源码包
读者可以从Source Bundle Releases页面(地址:http://jdk7.java.net/source.html)取得打包好的源码,到本地直接解压即可。
一般来说,源码包大概一至两个月左右会更新一次,虽然不够及时,但比起从Mercurial复制代码的确方便和快捷许多。
笔者下载的是OpenJDK 7 Update 6 Build b21版源码包,2012年8月28日发布,大概99MB,解压后约为339MB。
备注:推荐在linux平台或者mac平台上面编译jdk
3. JVM和Java HotSpot如何区分版本
你的虚拟机(JVM)版本是23.5-b02
java -version出来信息包含两部分:Java软件包发行版本信息和内核(JVM)版本信息。
java的发行包包含三种类型Java ME,Java SE,Java EE,发行包就相当于对外销售的产品包,不同发行包会删减部分特性,因此版本信息首先显示发行包类型和版本。
JVM是Java平台的基础和核心,一般在一个java大版本中JVM版本变化都是比较小的。HotSpot是一种JVM实现技术,相对以往的方式在性能和扩展能力上得到了很大的提升,因此它不是一个独立产品,可以理解Sun(Oracle)实现的JVM版本的品牌商标。
4. HotSpot实战的作品目录
第1章初识HotSpot
1.1JDK概述
1.1.1JCP与JSR
1.1.2JDK的发展历程
1.1.3Java 7的语法变化
1.2动手编译虚拟机
1.2.1源代码下载
1.2.2HotSpot源代码结构
1.2.3搭建编译环境
1.2.4编译目标
1.2.5编译过程
1.2.6编译常见问题
1.3实战:在HotSpot内调试HelloWorld
1.3.1认识GDB
1.3.2准备调试脚本
1.4小结
第2章启动
2.1HotSpot内核
2.1.1如何阅读源代码
2.1.2HotSpot内核框架
2.1.3Prims
2.1.4Services
2.1.5Runtime
2.2启动
2.2.1Launcher
2.2.2虚拟机生命周期
2.2.3入口:main函数
2.2.4主线程
2.2.5InitializeJVM函数
2.2.6JNI_CreateJavaVM函数
2.2.7调用Java主方法
2.2.8JVM退出路径
2.3系统初始化
2.3.1配置OS模块
2.3.2配置系统属性
2.3.3加载系统库
2.3.4启动线程
2.3.5vm_init_globals函数:初始化全局数据结构
2.3.6init_globals函数:初始化全局模块
2.4小结
第3章类与对象
3.1对象表示机制
3.1.1OOP-Klass二分模型
3.1.2Oops模块
3.1.3OOP框架与对象访问机制
3.1.4Klass与instanceKlass
3.1.5实战:用HSDB调试HotSpot
3.2类的状态转换
3.2.1入口:Class文件
3.2.2类的状态
3.2.3加载
3.2.4链接
3.2.5初始化
3.2.6实战:类的“族谱”
3.2.7实战:系统字典
3.3创建对象
3.3.1实例对象的创建流程
3.3.2实战:探测JVM内部对象
3.4小结
第4章运行时数据区
4.1堆
4.1.1Java的自动内存管理
4.1.2堆的管理
4.2线程私有区域
4.2.1PC
4.2.2JVM栈
4.3方法区
4.3.1纽带作用
4.3.2常量池
4.3.3常量池缓存:ConstantPoolCache
4.3.4方法的表示:methodOop
4.3.5方法的解析:将符号引用转换成直接引用
4.3.6代码放在哪里:ConstMethodOop
4.3.7实战:探测运行时常量池
4.4性能监控数据区:Perf Data
4.4.1描述这段空间:PerfMemory
4.4.2 查看
4.4.3 生产
4.5 转储
4.5.1 用VisualVM进行转储分析
4.5.2 JVM Crash
4.6 小结
第5章 垃圾收集
5.1 堆与GC
5.1.1 垃圾收集
5.1.2 分代收集
5.1.3 快速分配
5.1.4 栈上分配和逸出分析
5.1.5 GC公共模块
5.2 垃圾收集器
5.2.1 设计演进
5.2.2 CMS收集器
5.2.3 G1收集器
5.3 实战:性能分析方法
5.3.1 获取GC日志
5.3.2 GC监控信息
5.3.3 内存分析工具
5.3.4 选择合适的收集器与GC性能评估
5.3.5 不要忽略JVM Crash日志
5.4 小结
第6章 栈
6.1 硬件背景:了解真实机器
6.1.1 程序是如何运行的
6.1.2 x86与栈帧
6.1.3 ARM对Java硬件级加速:Jazelle技术
6.2 Java栈
6.2.1 寄存器式指令集与栈式指令集
6.2.2 HotSpot中的栈
6.2.3 栈帧
6.2.4 充分利用寄存器资源
6.2.5 虚拟机如何调用Java函数
6.2.6 优化:栈顶缓存
6.2.7 实战:操作数栈
6.3 小结
第7章 解释器和即时编译器
7.1 概述
7.2 解释器如何工作
7.2.1 Interpreter模块
7.2.2 Code模块
7.2.3 字节码表
7.2.4 Code Cache
7.2.5 InterpreterCodelet与Stubs队列
7.2.6 Code生成器
7.2.7 模板表与转发表
7.2.8 实战:InterpreterCodelet
7.3 即时编译器
7.3.1 概述
7.3.2 编译器模块
7.3.3 编译器的基本结构
7.3.4 实战:编译原理实践,了解编译中间环节
7.4 小结
第8章 指令集
8.1 再说栈式指令集
8.2 数据传送
8.2.1 局部变量、常量池和操作数栈之间的数据传送
8.2.2 数据传送指令
8.2.4 实战:数组的越界检查
8.3 类型转换
8.4 对象的创建和操作
8.5 程序流程控制
8.5.1 控制转移指令
8.5.2 条件转移
8.5.3 无条件转移
8.5.4 复合条件转移
8.5.5 实战:switch语句如何使用String
8.6 运算
8.6.1 加法:iadd
8.6.2 取负:ineg
8.7 函数的调用和返回
8.7.1 Java函数分发机制:VTABLE与ITABLE
8.7.2 invoke系列指令
8.7.3 动态分发:覆盖
8.7.4 静态分发:重载
8.8 异常
8.8.1 异常表
8.8.2 创建异常
8.8.3 try-catch
8.8.4 finally
8.9 小结
第9章 虚拟机监控工具
9.1 Attach机制
9.1.1 AttachProvider与VirtualMachine
9.1.2 命令的下发:execute()
9.1.3 命令的执行:Attach Listener守护线程
9.2 查看JVM进程
9.2.1 用jps查看Java进程
9.2.2 实战:定制jps,允许查看库路径
9.3 查看和配置JVM
9.3.1 用jinfo查看JVM参数配置
9.3.2 实战:扩展flags选项,允许查看命令行参数
9.4 堆内存转储工具
9.4.1 Heap Dump
9.4.2 原理
9.5 堆转储分析
9.5.1 Heap Dump分析工具:jhat
9.5.2 实战:MAT分析过程
9.6 线程转储分析
9.6.1 jstack
9.6.2 实战:如何分析资源等待
9.7 小结
5. 请教,推荐几本java类书籍
1、《Effective Java(第三版)》(Effective Java 3rd Edition)
如果你还没读过这本书,那它绝对是 2019 年你必须读的第一本书。第三版是一个长期版本,其实它早就该出版了。这版书也囊括了 JDK 7、8、9 的新特性。
我在 1 月份的第一个星期就拿到了这本书,它绝对是约书亚·布洛克(Joshua Bloch)给 Java 程序员非常好的新年礼物。
我花了大概一个星期就读完了这本书。我发现读的过程中,时常碰到新的知识点,特别是关于 Java 8 和 Java 9 的。
2、《写给大忙人看的Java SE 9(第二版)》 (Core Java SE 9 for the Impatient (2nd Edition))
如果你急着学 Java 那我推荐这本书给你。我是凯 S·霍斯特曼 (Cay S. Horstmann)的一个忠实粉丝,他的文采之优美、涉猎之广,都让我很是佩服。
你读了他写的关于 Java 8、Scala 的书以及《Java 核心编程》之后,绝对也会成为他的粉丝。这本书已经针对 Java SE 9 全面更新。如果你想学习 Java 9,那2018年你应该先读读这本书。
3、《Spring 微服务实战》(Spring Microservices in Action)
软件开发世界正在加速转向微服务架构,它在开发、维护、部署、扩容性及可靠性等方面有很多优势。
感谢 Spring framework 提供这么多开发微服务的 Java 工具,比如 Spring Boot 和 Spring Cloud。
如果你对用 Spring framework 开发微服务有兴趣,那么这本书很适合你。
2019年Java学习,依旧正在进行时,身为一个踏入Java坑的老码农,深感技术学习就是一个无底洞,需要不断的去挖掘新的技术,为了跟上时代的发展,需要时时关注技术更新,进行学习,不过随着技术的不断深入学习,收获还是不小的,正在向着资深技术官迈进!
6. Hotspot的源码应该怎样阅读
如果你下的只是HotSpot VM的代码的话那好办,Oracle JDK 6/Oracle JDK 7/OpenJDK 6/OpenJDK 7里的HotSpot VM基本上目录结构都是一样的。
├—agent Serviceability Agent的客户端实现
├—make 用来build出HotSpot的各种配置文件
├—src HotSpot VM的源代码
│ ├—cpu CPU相关代码(汇编器、模板解释器、ad文件、部分runtime函数在这里实现)
│ ├—os 操作系相关代码
│ ├—os_cpu 操作系统+CPU的组合相关的代码
│ └—share 平台无关的共通代码
│ ├—tools 工具
│ │ ├—hsdis 反汇编插件
│ │ ├—IdealGraphVisualizer 将server编译器的中间代码可视化的工具
│ │ ├—launcher 启动程序“java”
│ │ ├—LogCompilation 将-XX:+LogCompilation输出的日志(hotspot.log)整理成更容易阅读的格式的工具
│ │ └—ProjectCreator 生成Visual Studio的project文件的工具
│ └—vm HotSpot VM的核心代码
│ ├—adlc 平台描述文件(上面的cpu或os_cpu里的*.ad文件)的编译器
│ ├—asm 汇编器接口
│ ├—c1 client编译器(又称“C1”)
│ ├—ci 动态编译器的公共服务/从动态编译器到VM的接口
│ ├—classfile 类文件的处理(包括类加载和系统符号表等)
│ ├—code 动态生成的代码的管理
│ ├—compiler 从VM调用动态编译器的接口
│ ├—gc_implementation GC的实现
│ │ ├—concurrentMarkSweep Concurrent Mark Sweep GC的实现
│ │ ├—g1 Garbage-First GC的实现(不使用老的分代式GC框架)
│ │ ├—parallelScavenge ParallelScavenge GC的实现(server VM默认,不使用老的分代式GC框架)
│ │ ├—parNew ParNew GC的实现
│ │ └—shared GC的共通实现
│ ├—gc_interface GC的接口
│ ├—interpreter 解释器,包括“模板解释器”(官方版在用)和“C++解释器”(官方版不在用)
│ ├—libadt 一些抽象数据结构
│ ├—memory 内存管理相关(老的分代式GC框架也在这里)
│ ├—oops HotSpot VM的对象系统的实现
│ ├—opto server编译器(又称“C2”或“Opto”)
│ ├—prims HotSpot VM的对外接口,包括部分标准库的native部分和JVMTI实现
│ ├—runtime 运行时支持库(包括线程管理、编译器调度、锁、反射等)
│ ├—services 主要是用来支持JMX之类的管理功能的接口
│ ├—shark 基于LLVM的JIT编译器(官方版里没有使用)
│ └—utilities 一些基本的工具类
└—test 单元测试
你看到的目录结构应该是类似这样的
7. 程序开发中spring框架要怎么学习呢
1、打好基础是重中之重
基础部分可能很枯燥,但是一定要耐心坚持下去。因为打基础好比是在造轮子造汽车,没有打好基础在后面的学习就好比走路,可以说后面遇到的百分之七八十的问题都是基础没学好造成的。
2、多看官方文档多读源码
一定要看JDK相关类库、常用框架各种功能的源码,去了解其底层实现的原理。总的来说这个也是在打基础的部分,Java基础非常扎实才能看懂,在我们学习一个类的源码时,肯定会衍生出其他各种各样的问题,供我们来了解和学习,这也就是我们下一步学习的目标和方向。慢慢的,我们就会学习更多的知识,并积累更多的经验。
3、系统性学习,循序渐进
不要急于求成,每个知识点都要看,并且每个知识点都要勤加练习。有的同学在学习过程中觉得这个知识点简单,就跳着学习,其实这是个很大的问题,知识点细节必须要了解。我们学习Java需要循序渐进,一步一步来,不能操之过急。
4、遇到问题
遇到不会做的问题,当然不能置之不理。先在网上查,目前网络上针对很多问题都有完美的解决方案,如果网上没有类似的问题,那可能是你犯了什么小错误。也不要在这个问题上花费太多时间,这需要一定的学习技巧。Java中的知识有很强的相关性,有不懂的地方,可以用其他周边相关知识再回过头来理解,这样既不会耽误学习进度,又能理解自己不懂的地方
1)jvm有很多种,其实jvm是一个标准,sun做的那个叫hotspot,作者就是后来v8的作者lars bak,其他公司也做过jvm,其中做得比较好的有bea的jrockit,其他的包括ibm的r9,apple的jvm等在内,都做得不行,所以jvm主要是整合淘汰掉这些做得不好的jvm(s),整合成一个统一的openjdk。
2)java是典型的oop语言,其执行效率的优化,最早就是lars bak等人从smalltalk等长期优化的经验中总结出来并apply到hotspot上去滴,而smalltalk在早期apple机上搞出了那种拖拖拽拽就开发出app的做法,后来vc,delphi之类的其实都是抄袭或者说借鉴apple的smalltalk的做法,jobs说微软从头到尾都在抄袭apple是空穴来风,这里空穴来风跟王垠使用的空穴来风是一个意思,有趣的是,java的gui并没有继承这种搞法,反而对这种拖拖拽拽就作出app的做法批判有加,到今天,其实java的gui都还不能真正做到拖拖拽拽就作出来,问题很多,个人建议对于纯java的gui开发,还是以写代码为主。
3)jee也是一个或者说是一堆标准,知乎上有些人把maven,jenkins都算做jee是不对滴,jee的标准核心是ejb,其实就是一个xml配置化的java文件,这个标准在4的时候,达到了顶峰状态,几乎所有的挨踢大厂都主动支持该标准,之后开始走下坡路,支持的厂越来越少。
4)java和javascript的关系比很多人认为的要密切,javascript里面的java这四个字母可不是白叫的,比如js的版权和商标都控制在oracle手里,oracle对于js的支持甚至超过其对java的支持,并且喜欢捆绑销售,比如jvm里面就有一个js引擎。
5)jvm里面除了js engine以外还有一个浏览器排版引擎webkit,就是apple safari和google chrome用的那个那个。