性能文章>JDK13 GA发布:5大特性解读>

JDK13 GA发布:5大特性解读原创

2年前
737606

image.png
JDK13 GA版本 5大新特性如下:

350: Dynamic CDS Archives
351: ZGC: Uncommit Unused Memory
353: Reimplement the Legacy Socket API
354: Switch Expressions (Preview)
355: Text Blocks (Preview)

350: Dynamic CDS Archives

了解这个特性之前,需要先了解一下跟它有很大关联的特性JEP310:Application Class-Data Sharing,简称AppCDS。这个特性简介就是为了改善JVM应用的启动速度和内存占用,并且扩展了CDS(Class-Data Sharing)特性从而允许应用的类也可以被放置在共享的归档类(archived classes)文件中。

这个JEP310的主要目标如下:

  1. 通过共享不同Java进程之间通用的类元数据从而减少内存占用;
  2. 改进启动时间;
  3. 扩展CDS从而允许归档类被加载到自定义类加载器中;
  4. 扩展CDS允许归档类来自JDK运行时镜像文件($JAVA_HOME/lib/modules);

成功参考指标:

  1. 多JVM进程能够节省很大的内存空间;
  2. 进程的启动时间提升明显;

JEP350特性期望扩展CDS,从而允许在Java应用执行后进行动态类归档,归档的类将包括当前默认基础CDS归档中不存在的应用类和库中的类。这个特性的主要目标有:

  1. 提高CDS的可用性,消除了用户使用时为每个应用程序创建类列表(class list)的需要;
  2. 通过-Xshare:dump参数开启静态归档,包括内建的类加载器和用户自定义的类加载器。

在这之前,如果Java应用要使用CDS的话,3个步骤是必须的:

  1. 执行一次或者多次试运行,从而创建一个class list;
  2. 通过使用创建的class list来dump一个归档(archive);
  3. 用这个归档来运行;

使用示例:

# JVM退出时动态创建共享归档文件
bin/java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello
# 用动态创建的共享归档文件运行应用
bin/java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hell

351: ZGC: Uncommit Unused Memory

增强ZGC特性,将没有使用的堆内存归还给操作系统。ZGC当前不能把内存归还给操作系统,即使是那些很久都没有使用的内存,有点像貔貅一样,只进不出,哈哈。这种行为并不是对任何应用和环境都是友好的,尤其是那些内存占用敏感的服务,例如:

  1. 按需付费使用的容器环境;
  2. 应用可能长时间闲置,并且和很多其他应用共享和竞争资源的环境;
  3. 应用在执行期间有非常不同的堆空间需求,例如,可能在启动的时候比稳定运行的时候需要更多的内存。

HotSpot的G1和Shenandoah这两个GC已经提供了这种能力,并且对某些用户来说,非常有用。因此,把这个特性引入ZGC会得到这些用户的欢迎。

ZGC的堆由若干个Region组成,每个Region被称之为ZPage。每个Zpage与数量可变的已提交内存相关联。当ZGC压缩堆的时候,ZPage就会释放,然后进入page cache,即ZPageCache。这些在page cache中的ZPage集合就表示没有使用部分的堆,这部分内存应该被归还给操作系统。回收内存可以简单的通过从page cache中逐出若干个选好的ZPage来实现,由于page cache是以LRU顺序保存ZPage的,并且按照尺寸(小,中,大)进行隔离,因此逐出ZPage机制和回收内存相对简单了很多,主要挑战是设计关于何时从page cache中逐出ZPage的策略。

一个简单的策略就是设定一个超时或者延迟值,表示ZPage被驱逐前,能在page cache中驻留多长时间。这个超时时间会有一个合理的默认值,也可以通过JVM参数覆盖它。Shenandoah GC用了一个类型的策略,默认超时时间是5分钟,可以通过参数 -XX:ShenandoahUncommitDelay = milliseconds 覆盖默认值。

像上面这样的策略可能会运作得相当好。但是,用户还可以设想更复杂的策略:不需要添加任何新的命令行选项。例如,基于GC频率或某些其他数据找到合适超时值的启发式算法。JDK13将使用哪种具体策略目前尚未确定。可能最初只提供一个简单的超时策略,使用-XX:ZUncommitDelay = seconds选项,以后的版本会添加更复杂、更智能的策略(如果可以的话)。

uncommit能力默认是开启的,但是无论指定何种策略,ZGC都不能把堆内存降到低于Xms。这就意味着,如果Xmx和Xms相等的话,这个能力就失效了,-XX:-ZUncommit这个参数也能让这个内存管理能力失效。

353: Reimplement the Legacy Socket API

用一个易于维护和Debug的,更简单、更现代的实现来取代java.net.Socket和java.net.ServerSocket。Socket和ServerSocket可以追溯到JDK1.0,它们的实现混合了Java和C代码,维护和调试都非常痛苦。而且其实现用线程栈来进行IO buffer,导致某些场景需要调大Xss。

全新实现的NioSocketImpl,用来取代PlainSocketImpl,它的优点如下:

  1. 非常容易维护和Debug;
  2. 直接使用JDK的NIO实现,不需要自己的本地代码;
  3. 结合了buffer cache机制,所以不需要用线程栈来进行IO操作;
  4. 用JUC的锁取代synchronized修饰的方法;

354: Switch Expressions (Preview)

扩展Switch表达式,既能用陈述的方式,也能用表达式的方式。并且这两种形式都可以用传统方式(case … : labels),或者新的方式(case … -> labels),并且还准备引入表达式匹配(JEP305),类似这种玩法:

if (obj instanceof String s && s.length() > 5) {
    .. s.contains(..) ..
}

Switch表达式最初在JEP325中被提出,在JDK12中作为预览特性,根据反馈,这次的JEP354相比JEP325有一些改变,新版Switch表达式用法参考如下:

switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
    case TUESDAY                -> System.out.println(7);
    case THURSDAY, SATURDAY     -> System.out.println(8);
    case WEDNESDAY              -> System.out.println(9);
}
int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    case THURSDAY, SATURDAY     -> 8;
    case WEDNESDAY              -> 9;
};

355: Text Blocks (Preview)

即文本块。文本块就是指多行字符串,例如一段格式化后的xml、json等。用户不需要转义,Java能自动搞定。这个需求是承接自JEP326,JEP326已经废弃。

JEP326使用`这个符号,例如:

String html = `<html>
                   <body>
                       <p>Hello World.</p>
                   </body>
               </html>
              `;

JEP355使用"""这个符号,例如:

String html = """
               <html>
                   <body>
                       <p>Hello World.</p>
                   </body>
               </html>
              """;

JEP326废除的原因:
JEP326是把注意力放在字符串的原始性上,但是现在意识到这种关注是错误的。因为源码中原始字符串跨多行是很常见的,但是在内容中支付非转义分隔符的代码很大,这样的话,在用户使用多行字符串的时候,效率就会受到影响。原文如下:

because while raw string literals could easily span multiple lines of source code, the cost of supporting unescaped delimiters in their content was extreme. This limited the effectiveness of the feature in the multi-line use case

新版本文本块特性的目标:

  1. 简化表达多行字符串,不需要转义;
  2. 增强可读性;

接下来展示几种使用代码块特性前后的字符串申明方式。。

  • HTML示例

一维表达方式(旧):

String html = "<html>\n" +
              "    <body>\n" +
              "        <p>Hello, world</p>\n" +
              "    </body>\n" +
              "</html>\n";

二维表达方式(新):

String html = """
              <html>
                  <body>
                      <p>Hello, world</p>
                  </body>
              </html>
              """;
  • SQL示例

一维表达方式(旧):

String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
               "WHERE `CITY` = 'INDIANAPOLIS'\n" +
               "ORDER BY `EMP_ID`, `LAST_NAME`;\n";

二维表达方式(新):

String query = """
               SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
               WHERE `CITY` = 'INDIANAPOLIS'
               ORDER BY `EMP_ID`, `LAST_NAME`;
               """;

参考链接地址:https://openjdk.java.net/projects/jdk/13/

分类:
标签:
请先登录,再评论

暂无回复,快来写下第一个回复吧~

为你推荐

不起眼,但是足以让你收获的JVM内存案例
今天的这个案例我觉得应该会让你涨姿势吧,不管你对JVM有多熟悉,看到这篇文章,应该还是会有点小惊讶的,不过我觉得这个案例我分享出来,是想表达不管多么奇怪的现象请一定要追究下去,会让你慢慢变得强大起来,
字符串字面量长度是有限制的
前言 偶然在一次单元测试中写了一个非常长的字符串字面量。 正文 在一次单元测试中,我写了一个很长的字符串字面量,大概10万个字符左右,编译时,编译器给出了异常告警 `java: constant
多次字符串相加一定要用StringBuilder而不用-吗?
今天在写一个读取Java class File并进行分析的Demo时,偶然发现了下面这个场景(基于oracle jdk 1.8.0_144): ``` package test; public c
如何通过反射获得方法的真实参数名(以及扩展研究)
前段时间,在做一个小的工程时,遇到了需要通过反射获得方法真实参数名的场景,在这里我遇到了一些小小的问题,后来在部门老大的指导下,我解决了这个问题。通过解决这个问题,附带着我了解到了很多新的知识,我觉得
谨防JDK8重复类定义造成的内存泄漏
概述 如今JDK8成了主流,大家都紧锣密鼓地进行着升级,享受着JDK8带来的各种便利,然而有时候升级并没有那么顺利?比如说今天要说的这个问题。我们都知道JDK8在内存模型上最大的改变是,放弃了Perm
JDK13 GA发布:5大特性解读
JDK13 GA版本 5大新特性如下: 350: Dynamic CDS Archives 351: ZGC: Uncommit Unused Memory 353: Reimplement the
译:谁是 JDK8 中最快的 GC
我们都知道 OpenJDK8 有好几个垃圾回收算法,比如 ParallelGC,CMS,还有 G1,那么哪个才是最快的?如果 GC 算法从 Java8 中默认的 ParallelGC 切换到 G1 会
Javassist实现JDK动态代理
提到JDK动态代理,相信很多人并不陌生。然而,对于动态代理的实现原理,以及如何编码实现动态代理功能,可能知道的人就比较少了。接下一来,我们就一起来看看JDK动态代理的基本原理,以及如何通过Javass