Java11 - 新特性
笔记
从版本地位来看,Java 11 是和 Java 8 一个定位,属于长期支持版本,也就是说它将会与 Java 8 一样,成为企业常用、稳定的 JDK 版本。
本内容涉及实际编写代码的是新增字符串处理方法、Optional 加强、全新 HTTP 客户端。
2022-02-08 @Young Kbt
# Java11概述
北京时间 2018 年 9 月 26 日,Oracle 官方宣布 Java 11 正式发布。这是 Java 大版本周期变化后的第一个长期支持版本,非常值得关注。从官网即可下载,最新发布的 Java11 将带来 ZGC、Http Client 等重要特性,一共包含 17 个 JEP(JDK Enhancement Proposals,JDK 增强提案)。
Features | 官网文档地址 |
---|---|
JEP 181: Nest-Based Access Control | http://openjdk.java.net/jeps/181 |
JEP 309: Dynamic Class-File Constants | http://openjdk.java.net/jeps/309 |
JEP 315: Improve Aarch64 Intrinsics | http://openjdk.java.net/jeps/315 |
JEP 318: Epsilon: A No-Op Garbage Collector | http://openjdk.java.net/jeps/318 |
JEP 320: Remove the Java EE and CORBA Modules | http://openjdk.java.net/jeps/320 |
JEP 321: HTTP Client (Standard) | http://openjdk.java.net/jeps/321 |
JEP 323: Local-Variable Syntax for Lambda Parameters | http://openjdk.java.net/jeps/323 |
JEP 324: Key Agreement with Curve25519 and Curve448 | http://openjdk.java.net/jeps/324 |
JEP 327: Unicode 10 | http://openjdk.java.net/jeps/327 |
JEP 328: Flight Recorder | http://openjdk.java.net/jeps/328 |
JEP 329: ChaCha20 and Poly1305 Cryptographic Algorithms | http://openjdk.java.net/jeps/329 |
JEP 330: Launch Single-File Source-Code Programs | http://openjdk.java.net/jeps/330 |
JEP 331: Low-Overhead Heap Profiling | http://openjdk.java.net/jeps/331 |
JEP 332: Transport Layer Security (TLS) 1.3 | http://openjdk.java.net/jeps/332 |
JEP 333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental) | http://openjdk.java.net/jeps/333 |
JEP 335: Deprecate the Nashorn JavaScript Engine | http://openjdk.java.net/jeps/335 |
JEP 336: Deprecate the Pack200 Tools and API | http://openjdk.java.net/jeps/336 |
JDK 11 将是一个 企业不可忽视 的版本。从时间节点来看,JDK 11 的发布正好处在 JDK 8 免费更新到期的前夕,同时 JDK 9、10 也陆续成为 历史版本,下面是 Oracle JDK 支持路线图:
JDK 更新很重要吗?非常重要,在过去的很多年中,Oracle 和 OpenJDK 社区提供了接近免费的午餐,导致人们忽略了其背后的海量工作和价值,这其中包括但不仅仅限于:最新的安全更新,如,安全协议等基础设施的升级和维护,安全漏洞的及时修补,这是 Java 成为企业核心设施的基础之一。大量的新特性、Bug 修复,例如,容器环境支持,GC 等基础领域的增强。很多生产开发中的 Hack,其实升级 JDK 就能解决了。不断改进的 JVM,提供接近零成本的性能优化...
JDK 11 是一个长期支持版本(LTS, Long-Term-Support)
对于企业来说,选择 11 将意味着长期的、可靠的、可预测的技术路线图。其中免费的 OpenJDK11 确定将得到 OpenJDK 社区的长期支持,LTS 版本将是可以放心选择的版本。
从 JVM GC 的角度,JDK11 引入了两种新的 GC,其中包括也许是划时代意义的 ZGC,虽然其目前还是实验特性,但是从能力上来看,这是 JDK 的一个巨大突破,为特定生产环境的苛刻需求提供了一个可能的选择。例如,对部分企业核心存储等产品,如果能够保证不超过 10ms 的 GC 暂停,可靠性会上一个大的台阶,这是过去我们进行 GC 调优几乎做不到的,是能与不能的问题。
对于 G1 GC,相比于 JDK 8,升级到 JDK 11 即可免费享受到:并行的 Full GC,快速的 CardTable 扫描,自适应的堆占用比例调整(IHOP),在并发标记阶段的类型卸载等等。这些都是针对 G1 的不断增强,其中串行 Full GC 等甚至是曾经被广泛诟病的短板,你会发现 GC 配置和调优在 JDK11 中越来越方便。
云计算时代的监控、诊断和 Profiling 能力,这个是相比 ZGC 更具生产实践意义的特性。
Java 的应用场景跨度很大,从单机长时间运行的 Java 应用,发展成为分布式、大的单体应用或小的 function、瞬时或长时间运行等,应用场景非常复杂。
我们用什么工具诊断 Java 应用?
JDK 11 为我们提供了更加强大的基础能力,主要是两部分:
JEP 328:Flight Recorder(JFR):是 Oracle 刚刚开源的强大特性
JFR 是一套集成进入 JDK、JVM 内部的事件机制框架,通过良好架构和设计的框架,硬件层面的极致优化,生产环境的广泛验证,它可以做到极致的可靠和低开销。在 SPECjbb2015 等基准测试中,JFR 的性能开销最大不超过 1%,所以,工程师可以基本没有心理负担地在大规模分布式的生产系统使用,这意味着,我们既可以随时主动开启 JFR 进行特定诊断,也可以让系统长期运行 JFR,用以在复杂环境中进行「After-the-fact」分析。
在保证低开销的基础上,JFR 提供的能力可以应用在对锁竞争、阻塞、延迟,JVM GC、SafePoint 等领域,进行非常细粒度分析。甚至深入 JIT Compiler 内部,全面把握热点方法、内联、逆优化等等。JFR 提供了标准的 Java、C++ 等扩展 API,可以与各种层面的应用进行定制、集成,为复杂的企业应用栈或者复杂的分布式应用,提供 All-in-One 解决方案。
而这一切都是内建在 JDK 和 JVM 内部的,并不需要额外的依赖,开箱即用。
JEP 331: Low-Overhead Heap Profiling
它来源于 Google 等业界前沿厂商的一线实践,通过获取对象分配细节,为 JDK 补足了对象分配诊断方面的一些短板,工程师可以通过 JVMTI 使用这个能力增强自身的工具。
从 Java 类库发展的角度来看,JDK 11 最大的进步也是两个方面:
第一,HTTP/2 Client API,新的 HTTP API 提供了对 HTTP/2 等业界前沿标准的支持,精简而又友好的 API 接口,与主流开源 API(如,Apache HttpClient, Jetty, OkHttp 等)对等甚至更高的性能。与此同时它是 JDK 在 Reactive-Stream 方面的第一个生产实践,广泛使用了 Java Flow API 等,终于让 Java 标准 HTTP 类库在扩展能力等方面,满足了现代互联网的需求。
第二,就是安全类库、标准等方面的大范围升级,其中特别是 JEP 332: Transport Layer Security (TLS) 1.3,除了在安全领域的重要价值,它还是中国安全专家范学雷所领导的 JDK 项目,完全不同于以往的修修补补,是个非常大规模的工程。
除此之外,JDK 还在逐渐进行瘦身工作,或者偿还 JVM、Java 规范等历史欠账,例如:
335: Deprecate the Nashorn JavaScript Engine
它进一步明确了 Graal 很有可能将成为 JVM 向前演进的核心选择,Java-on-Java 正在一步步的成为现实。
# Dynamic Class-File Constants
这是类文件新添的一种结构。具体看官方的介绍:http://openjdk.java.net/jeps/309
Java 的类型文件格式将被拓展,支持一种新的常量池格式:CONSTANT_Dynamic,加载 CONSTANT_Dynamic 会将创建委托给 bootstrap 方法。
其目标是降低开发新形式的可实现类文件约束带来的成本和干扰。
# 新增字符串处理方法
判断字符串是否为空白
isBlank()
public void test() {
String str = "\t \r\n ";
// 判断字符串的内容是否都是空白
System.out.println(str.isBlank()); // 输出:true
}
2
3
4
5
去除首尾空白
strip()
和 trim()
的区别在于,strip()
去除字符串首尾的空白,包括英文和其他所有语言中的空白字符,而 trim()
去除字符串首尾的空白,只能去除码值小于等于 32 的空白字符,如中文空格无法去除。
public void test() {
// 去除字符串首尾的空白,包括英文和其他所有语言中的空白字符
String str1 = " youngkbt.cn ".strip();
System.out.println(str1); // 输出:youngkbt.cn
// 去除字符串首尾的空白,只能去除码值小于等于 32 的空白字符,如中文空格无法去除
String str2 = " youngkbt.cn ".trim();
System.out.println(str2); // 输出:youngkbt.cn
}
2
3
4
5
6
7
8
9
去除尾部空白
stripTrailing()
相比较 strip()
,只是去除了尾部的空白。
public void test() {
// 去除字符串尾部的空白
String str = " youngkbt.cn ".stripTrailing();
System.out.println(str1); // 输出: youngkbt.cn
}
2
3
4
5
去除首部空白
stripLeading()
相比较 strip()
,只是去除了首部的空白。
public void test() {
// 去除字符串首部的空白
String str = " youngkbt.cn ".stripLeading();
System.out.println(str1); // 输出:youngkbt.cn
}
2
3
4
5
复制字符串
repeat()
public void test() {
// 复制字符串 3 次
String str = "youngkbt.cn".repeat(3);
System.out.println(str1); // 输出:youngkbt.cnyoungkbt.cnyoungkbt.cn
}
2
3
4
5
行数统计
lines().count()
注意是行数的统计,而不是字数的统计。
public void test() {
long count = "ABC".lines().count();
System.out.println(count); // 输出:1
long count = "A\nB\nC".lines().count();
System.out.println(count); // 输出:3
}
2
3
4
5
6
7
lines()
有一个很有用的用途,就是读取文件的内容,如:
public void test() {
FileInputStream fis = new FileInputStream("文件路径");
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
String str = new String(buffer);
str.lines().forEach(System.out::println);
}
2
3
4
5
6
7
8
9
# Optional加强
Optional 也增加了几个非常酷的方法,现在可以很方便的将一个 Optional 转换成一个 Stream,或者当一个空 Optional 时给它一个替代的。
新增方法 | 描述 | 新增的版本 |
---|---|---|
isEmpty() | 判断 value 是否为空 | JDK 11 |
ifPresentOrElse(参数 1, 参数 2) | value 非空,执行参数 1 功能;如果 value 为空,执行参数2 功能 | JDK 9 |
or() | value 非空,返回对应的 Optional;value 为空,返回形参封装的 Optional | JDK 9 |
stream() | value 非空,返回仅包含此 value 的 Stream;否则,返回一个空的 Stream | JDK 9 |
orElseThrow() | value 非空,返回 value;否则抛异常 NoSuchElementException | JDK 10 |
代码示例:
public void test() {
Optional<Object> op = Optional.empty();
// 判断内部的 value 是否存在
System.out.println(op.isPresent()); // 输出:false
// 判断内部的 value 是否为空
System.out.println(op.isEmpty()); // 输出:true
op = Optional.of( "abc" ) ;
// orELseThrow():value 非空,返回 value;否则抛异常 NoSuchELementException
var obj = op.orElseThrow();
System.out.println(obj);
Optional<String> op1 = Optional.of( "hello" );
// or:value 非空,返回对应的 optional;value 为空,返回形参封装的 optional
Optional<object> op2 = op.or(() -> op1);
system.out.println(op2); // sOptional[abc]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 局部变量类型推断升级
在 var 上添加注解的语法格式,在 Java10 中是不能实现的。在 Java11 中加入了这样的语法。
在声明隐式类型的 lambda 表达式的形参时允许使用 var,使用 var 的好处是在使用 lambda 表达式时给参数加上注解,如下:
Consumer<String> consumer = (@Deprecated var x, @Nullable var y) -> x.process(y);
因为不使用 var 的话,是会报错 非法的表达式开始,如下:
Consumer<String> consumer = (@Deprecated x, @Nullable y) -> x.process(y);
# 全新HTTP客户端
HTTP,用于传输网页的协议,早在 1997 年就被采用在目前的 1.1 版本中。直到 2015 年,HTTP2 才成为标准。
HTTP/1.1 和 HTTP/2 的主要区别是如何在客户端和服务器之间构建 和传输数据。HTTP/1.1 依赖于请求/响应周期。HTTP/2 允许服务器 push
数据:它可以发送比客户端请求更多的数据。这使得它可以优先处理并发送对于首先加载网页至关重要的数据。
这是 Java 9 开始引入的一个处理 HTTP 请求的的 HTTP Client API,该 API 支持同步和异步,而在 Java 11 中已经成为正式可用状态,你可以在 java.net 包中找到这个 API。
它将 替代仅适用于 blocking 模式的 HttpURLConnection
(HttpURLConnection 是在 HTTP 1.0 的时代创建的,并使用了协议无关的方法),并提供 对 WebSocket 和 HTTP/2 的支持。
来看一下 HTTP Client 的同步和异步用法:
同步 HTTP
public void testHttp() throws Exception { // 1. 创建客户端 HttpClient httpClient = HttpClient.newHttpClient(); // 2. 创建访问地址的对象 HttpRequest request = HttpRequest.newBuilder(URI.create("http://www.youngkbt.cn")).GET().build(); // 3. 创建能处理地址返回结果的对象 HttpResponse.BodyHandler<String> responseBodyHandler = HttpResponse.BodyHandlers.ofString(); // 4. 发送请求,获取响应 HttpResponse<String> response = httpClient.send(request, responseBodyHandler); // 5. 输出响应内容 System.out.println(response.body()); }
1
2
3
4
5
6
7
8
9
10
11
12上面的
.GET()
可以省略,默认请求方式为 GET。异步 HTTP
public void testHttpAsync() throws Exception { // 1. 创建客户端 HttpClient httpClient = HttpClient.newHttpClient(); // 2. 创建访问地址的对象 HttpRequest request = HttpRequest.newBuilder(URI.create("http://www.youngkbt.cn")).GET().build(); // 3. 创建能处理地址返回结果的对象 HttpResponse.BodyHandler<String> responseBodyHandler = HttpResponse.BodyHandlers.ofString(); // 4. 发送请求,获取响应 CompletableFuture<HttpResponse<String>> response = httpClient.sendAsync(request, responseBodyHandler); // 5. 异步获取并输出响应内容 System.out.println(response.get().body()); }
1
2
3
4
5
6
7
8
9
10
11
12
# 移除的一些内容
# 移除项
- 移除了
com.sun.awt.AWTUtilities
- 移除了
sun.misc.Unsafe.defineClass
,使用java.lang.invoke.MethodHandles.Lookup.defineClass
来替代 - 移除了
Thread.destroy()
以及Thread.stop(Throwable)
方法 - 移除了
sun.nio.ch.disableSystemWideOverlappingFileLockCheck
、sun.locale.formatasdefault
属性 - 移除了
jdk.snmp
模块 - 移除了
javafx
,OpenJDK 在 Java10 版本就移除了,但是 Oracle JDK10 还尚未移除 javafx,而 Oracle JDK11 版本移除了 javafx - 移除了
Java Mission Control
,从 JDK 中移除之后,需要自己单独下载 - 移除了这些
Root Certificates
:Baltimore Cybertrust Code Signing CA,SECOM,AOL and Swisscom
# 废弃项
-XX+AggressiveOpts
选项-XX:+UnlockCommercialFeatures
选项-XX:+LogCommercialFeatures
选项
# 更简化的编译运行程序
JEP 330: 增强 Java 启动器支持运行单个 Java 源代码文件的程序。
在 Java 11 之前,我们要想运行一个 Java 文件,首先利用 javac
将 Java 文件编译处 Class 文件,再 java
来运行 Class 文件,而在 Java 11 中,我们可以直接使用 java
对一个 Java 文件运行,不需要编译成 Class 文件,也不会在目录下生成 Class 文件。
注意点:
- 执行源文件中的第一个类,第一个类必须包含主方法
- 并且不可以使用别源文件中的自定义类,本文件中的自定义类是可以使用的
假设有一个 Java 文件,在命令行使用 java TestJava
就会输出 Hello,Java 11
,内容如下:
public class TestJava {
public static void main(String[] args) {
System.out.println("Hello,Java 11");
}
}
2
3
4
5
如果该文件有两个类,默认是使用第一个类,如果第一个类没有 main
主方法,则报错,如下的命令 java TestJava
将输出 Java 11
:
class TestJava1 {
public static void main(String[] args) {
System.out.println("Java 11");
}
}
public class TestJava {
public static void main(String[] args) {
System.out.println("Hello,Java 11");
}
}
2
3
4
5
6
7
8
9
10
如果该文件有一个类引用自定义类,则确保自定义类在该文件里,无法跨文件使用,如下:
class Teacher {
private String name;
private int age;
}
public class TestJava {
public static void main(String[] args) {
Teacher teacher = new Teacher();
}
}
2
3
4
5
6
7
8
9
# Unicode 10
Unicode 10 增加了 8518 个字符,总计达到了 136690 个字符。并且增加了 4 个脚本.同时还有 56 个新的 emoji 表情符号。
因此 Java11 新增了四个 Java 文件。
# 移除JavaEE和CORBA模块
在 Java11 中移除了不太使用的 JavaEE 模块和 CORBA 技术。
CORBA 来自于二十世纪九十年代,Oracle 说,现在用 CORBA 开发现代 Java 应用程序已经没有意义了,维护 CORBA 的成本已经超过了保留它带来的好处。
但是删除 CORBA 将使得那些依赖于 JDK 提供部分 CORBA API 的 CORBA 实现无法运行。目前还没有第三方 CORBA 版本,也不确定是否会有第三方愿意接手 CORBA API 的维护工作。
在 Java11 中将 Java9 标记废弃的 Java EE 及 CORBA 模块移除掉,具体如下:
java.xml.ws
java.xml.bind
java.xml.ws
java.xml.ws.annotation
jdk.xml.bind
jdk.xml.ws
java.corba
java.se.ee
java.activation
java.transactio
2
3
4
5
6
7
8
9
10
11
只剩下 java.xml
,java.xml.crypto
,jdk.xml.dom
这几个模块。但是 Java 11 新增一个 java.transaction.xa
模块。
# 废弃Nashorn JavaScript引擎
废除 Nashorn javascript 引擎,在后续版本准备移除掉,有需要的可以考虑使用 GraalVM。
# 废弃Pack20工具和API
Java5 中带了一个压缩工具:Pack200,这个工具能对普通的 jar 文件进行高效压缩。其实现原理是根据 Java 类特有的结构,合并常数池,去掉无用信息等来实现对 Java 类的高效压缩。由于是专门对 Java 类进行压缩的,所以对普通文件的压缩和普通压缩软件没有什么两样,但是对于 Jar 文件却能轻易达到 10% - 40% 的压缩率。这在 Java 应用部署中很有用,尤其对于移动 Java 计算,能够大大减小代码下载量。
Java5 中还提供了这一技术的 API 接口,你可以将其嵌入到你的程序中使用。使用的方法很简单,下面的短短几行代码即可以实现 jar 的压缩和解压:
// 压缩
Packer packer = Pack200.newPacker();
OutputStream output = new BufferedOutputStream(new FileOutputStream(outfile));
packer.pack(new JarFile(jarFile), output);
output.close();
// 解压
Unpacker unpacker = Pack200.newUnpacker();
output = new JarOutputStream(new FileOutputStream(jarFile));
unpacker.unpack(pack200File, output);
output.close();
2
3
4
5
6
7
8
9
10
11
Pack200 的压缩和解压缩速度是比较快的,而且压缩率也是很惊人的,在我是使用的包 4.46MB 压缩后成了 1.44MB(0.322%),而且随着包的越大压缩率会根据明显,据说如果 jar 包都是 Class 类可以压缩到 1/9 的大小。其实 Java WebStart 还有很多功能,例如可以按不同的 jar 包进行 lazy 下载和单独更新,设置可以根据 jar 中的类变动进行 Class 粒度的下载。
但是在 Java11 中废除了 Pack200 以及 Unpack200 工具以及 java.util.jar
中的 Pack200 API。因为 Pack200 主要是用来压缩 jar 包的工具,由于网络下载速度的提升以及 Java9 引入模块化系统之后不再依赖 Pack200,因此这个版本将其移除掉。
# Epsilon垃圾收集器
A NoOp Garbage Collector。
JDK 对这个特性的描述是:开发一个处理内存分配但不实现任何实际内存回收机制的 GC,一旦可用堆内存用完,JVM 就会退出。
如果有 System.gc()
调用,实际上什么也不会发生(这种场景下和 -XX:+DisableExplicitGC
:禁用 GC 效果一样),因为没有内存回收,这个实现可能会警告用户尝试强制 GC 是徒劳。
# 用法参数
两个参数一起使用。
-XX:+UnlockExperimentalVMOptions
- ``-XX:+UseEpsilonGC`
class Garbage {
int n = (int)(Math.random() * 100);
@Override
public void finalize() {
System.out.println(this + " : " + n + " is dying");
}
}
public class EpsilonTest {
public static void main(String[] args) {
boolean flag = true;
List<Garbage> list = new ArrayList<>();
long count = 0;
while (flag) {
list.add(new Garbage());
if (list.size() == 1000000 && count == 0) {
list.clear();
count++;
}
}
System.out.println("程序结束");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
如果使用选项 -XX:+UseEpsilonGC
,程序很快就因为堆空间不足而退出,因为该 GC 并不会进行垃圾回收。
使用这个选项的原因
提供完全被动的 GC 实现,具有有限的分配限制和尽可能低的延迟开销,但代价是内存占用和内存吞吐量。
众所周知,Java 实现可广泛选择高度可配置的 GC 实现。各种可用的收集器最终满足不同的需求,即使它们的可配置性使它们的功能相交。有时更容易维护单独的实现,而不是在现有 GC 实现上堆积另一个配置选项。
# 主要用途
- 性能测试(它可以帮助过滤掉 GC 引起的性能假象)
- 内存压力测试(例如,知道测试用例应该分配不超过 1GB 的内存,我们可以使用
-Xmx1g
和–XX:+UseEpsilonGC
,如果程序有问题,则程序会崩溃) - 非常短的 JOB 任务(对象这种任务,接受 GC 清理堆那都是浪费空间)
- VM 接口测试
- Last-drop 延迟 & 吞吐改进
# ZGC垃圾收集器
GC 是 Java 主要优势之一。然而,当 GC 停顿太长,就会开始影响应用的响应时间.消除或者减少 GC 停顿时长,Java 将对更广泛的应用场景是一个更有吸引力的平台。此外,现代系统中可用内存不断增长,用户和程序员希望 JVM 能够以高效的方式充分利用这些内存,并且无需长时间的 GC 暂停时间。
ZGC:A Scalable Low-Latency Garbage Collector(Experimental),这应该是 JDK11 最为瞩目的特性,没有之一。但是后面带了 Experimental,说明这还不建议用到生产环境。
特点:
- GC 暂停时间不会超过 10ms
- 既能处理几百兆的小堆,也能处理几个 T 的大堆(OMG)
- 和 G1 相比,应用吞吐能力不会下降超过 15%
- 为未来的 GC 功能和利用 colord 指针以及 Load barriers 优化奠定基础
- 初始只支持 64 位系统
ZGC 的设计目标是:支持 TB 级内存容量,暂停时间低(<10ms),对整个程序吞吐量的影响小于 15%。 将来还可以扩展实现机制,以支持不少令人兴奋的功能,例如多层堆(即热对象置于 DRAM 和冷对象置于 NVMe 闪存),或压缩堆。
ZGC 是一个并发,基于 region,压缩型的垃圾收集器,只有 root 扫描阶段会 STW,因此 GC 停顿时间不会随着堆的增长和存活对象的增长而变长。
用法(两个都要使用):
-XX:+UnlockExperimentalVMOptions
,因为 ZGC 还处于实验阶段,所以需要通过 JVM 参数来解锁这个特性–XX:+UseZGC
# 支持G1上的并行完全垃圾收集
对于 G1 GC,相比于 JDK 8,升级到 JDK 11 即可免费享受到:并行的 Full GC,快速的 CardTable 扫描,自适应的堆占用比例调整(IHOP),在并发标记阶段的类型卸载等等。这些都是针对 G1 的不断增强,其中串行 Full GC 等甚至是曾经被广泛诟病的短板,你会发现 GC 配置和调优在 JDK11 中越来越方便。
# 免费的低耗能飞行记录仪和堆分析仪
低耗能飞行记录仪和堆分析仪通过 JVMTI 的 SampledObjectAlloc 回调提供一个低开销的,为了排错 Java 应用问题,以及 JVM 问题的数据收集框架。
希望达到的目标如下:
- 提供用于生产和消费数据作为事件的API
- 提供缓存机制和二进制数据格式
- 允许事件配置和事件过滤
- 提供 OS,JVM 和 JDK 库的事件
# 两种加密算法
Java 11 实现了 RFC 7539 的 ChaCha20 and ChaCha20-Poly1305 加密算法 XECPublicKey
和 XECPrivateKey
,代替 RC4。
RFC7748 定义的秘钥协商方案更高效,更安全。JDK 增加两个新的接口
// XECPublicKey 和 XECPrivateKey
KeyPairGenerator kpg = KeyPairGenerator.getInstance("XDH");
NamedParameterSpec paramSpec = new NamedParameterSpec("X25519");
kpg.initialize(paramSpec);
KeyPair kp = kgp.generateKeyPair();
KeyFactory kf = KeyFactory.getInstance("XDH");
BigInteger u = new BigInteger("xxx");
XECPublicKeySpec pubSpec = new XECPublicKeySpec(paramSpec, u);
PublicKey pubKey = kf.generatePublic(pubSpec);
KeyAgreement ka = KeyAgreement.getInstance("XDH");
ka.init(kp.getPrivate());
ka.doPhase(pubKey, true);
byte[] secret = ka.generateSecret();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 新的默认根权限证书集
Java 11 实现 TLS 协议 1.3 版本,TLS 允许客户端和服务器端通过互联网以一种防止窃听,篡改以及消息伪造的方式进行通信。
# Java Flight Recorder
Flight Recorder 源自飞机的黑盒子。
Flight Recorder 以前是商业版的特性,在 Java11 当中开源出来,它可以导出事件到文件中,之后可以用 Java Mission Control 来分析。可以在应用启动时配置 java -XX:StartFlightRecording
,或者在应用启动之后,使用 jcmd 来录制,比如:
jcmd <pid> JFR.start
,开启 Flight Recorder ,监听 Java 程序的 pidjcmd <pid> JFR.dump filename=recording.jfr
,将监听到的数据写入 JFR 文件,并继续监听新的数据jcmd <pid> JFR.stop
,关闭 Flight Recorder
Flight Recorder 是 Oracle 刚刚开源的强大特性。我们知道在生产系统进行不同角度的 Profiling,有各种工具、框架,但是能力范围、可靠性、开销等,大都差强人意,要么能力不全面,要么开销太大,甚至不可靠可能导致 Java 应用进程宕机。
而 JFR 是一套集成进入 JDK、JVM 内部的事件机制框架,通过良好架构和设计的框架,硬件层面的极致优化,生产环境的广泛验证,它可以做到极致的可靠和低开销。在 SPECjbb2015 等基准测试中,JFR 的性能开销最大不超过 1%,所以,工程师可以基本没有心理负担地在大规模分布式的生产系统使用,这意味着,我们既可以随时主动开启 JFR 进行特定诊断,也可以让系统长期运行 JFR,用以在复杂环境中进行「After-the-fact」分析。还需要苦恼重现随机问题吗?JFR 让问题简化了很多。
在保证低开销的基础上,JFR 提供的能力也令人眼前一亮,例如:我们无需 BCI 就可以进行 Object Allocation Profiling,终于不用担心 BTrace 之类把进程搞挂了。对锁竞争、阻塞、延迟,JVM GC、SafePoint 等领域,进行非常细粒度分析。甚至深入 JIT Compiler 内部,全面把握热点方法、内联、逆优化等等。JFR 提供了标准的 Java、C++ 等扩展 API,可以与各种层面的应用进行定制、集成,为复杂的企业应用栈或者复杂的分布式应用,提供 All-in-One 解决方案。而这一切都是内建在 JDK 和 JVM 内部的,并不需要额外的依赖,开箱即用。