Lambda初次使用很慢?从JIT到类加载再到实现原理

从JIT到类加载再到实现原理解式Lambda编译慢的问题 问题回顾 描述的话不多说,直接上图: 看到输出结果了吗?为什么第一次和第二次的时间相差如此之多?咱们一起琢磨琢磨,也可以先去看看结论再回过头看分析 注:并非仅第二次快,而是除了第一次,之后的每一次都很快 给与猜想 是否和操作系统预热有关? 是否和JIT(即时编译)有关? 是否和ClassLoader类加载有关? 是否和Lambda有关,并非foreach的问题 验证猜想 操作系统预热 操作系统预热这个概念是我咨询一位大佬得到的结论,在百度 / Google 中并未搜索到相应的词汇,但是在模拟测试中 阅读详情

问题回顾

描述的话不多说,直接上图:

看到输出结果了吗?为什么第一次和第二次的时间相差如此之多?咱们一起琢磨琢磨,也可以先去看看结论再回过头看分析

注:并非仅第二次快,而是除了第一次,之后的每一次都很快

给与猜想

  1. 是否和操作系统预热有关?
  2. 是否和JIT(即时编译)有关?
  3. 是否和ClassLoader类加载有关?
  4. 是否和Lambda有关,并非foreach的问题

验证猜想

操作系统预热

操作系统预热这个概念是我咨询一位大佬得到的结论,在百度 / Google 中并未搜索到相应的词汇,但是在模拟测试中,我用 普通遍历 的方式进行测试:

基本上每次都是前几次速度较慢,后面的速度更快,因此 可能 有这个因素影响,但差距并不会很大,因此该结论并不能作为问题的答案。

JIT 即时编译

首先介绍一下什么是JIT即时编译:

当 JVM 的初始化完成后,类在调用执行过程中,执行引擎会把字节码转为机器码,然后在操作系统中才能执行。在字节码转换为机器码的过程中,虚拟机中还存在着一道编译,那就是即时编译。

最初,JVM 中的字节码是由解释器( Interpreter )完成编译的,当虚拟机发现某个方法或代码块的运行特别频繁的时候,就会把这些代码认定为热点代码。

为了提高热点代码的执行效率,在运行时,即时编译器(JIT,Just In Time)会把这些代码编译成与本地平台相关的机器码,并进行各层次的优化,然后保存到内存中

再来一个概念,回边计数器

回边计数器用于统计一个方法中循环体代码执行的次数,在字节码中遇到控制流向后跳转的指令称为 “回边”(Back Edge)

建立回边计数器的主要目的是为了触发 OSR(On StackReplacement)编译,即栈上编译,在一些循环周期比较长的代码段中,当循环达到回边计数器阈值时,JVM 会认为这段是热点代码,JIT 编译器就会将这段代码编译成机器语言并缓存,在该循环时间段内,会直接将执行代码替换,执行缓存的机器语言

从上述的概念中,我们应该可以得到一个结论:第一条所谓的操作系统预热 大概率不正确,因为普通遍历方法执行N次,后续执行的时间占用比较小,很可能是因为JIT导致的。

那 JIT即时编译 是否是最终的答案?我们想办法把 JIT 关掉来测试一下,通过查询资料发现了如下内容:

Procedure

  • Use the -D option on the JVM command line to set the java.compiler property to NONE or the empty string.

    Type the following command at a shell or command prompt:

java -Djava.compiler=NONE <class>

注:该段内容来自IBM官方资料,地址见 <收获> ,咱们先不要停止思考

通过配置 IDEA JVM 参数:

执行问题中的代码测试结果如下:

# 禁用前
foreach time one: 38
分割线...
foreach time two: 1

# 禁用后
foreach time one: 40
分割线...
foreach time two: 5

我测试了很多次,结果都很相近,因此得到可以得到另一个结论:JIT并非引发该问题的原因(但是它的确能提高执行效率)

难道和类加载有关?

在进行类加载验证时,我依然无法放弃 JIT ,因此查阅了很多资料,知道了某个命令可以查看 JIT编译的耗时情况,命令如下:

java -XX:+CITime com.code.jvm.preheat.Demo >> log.txt

解释一下命令的意思

# 执行的目录
C:\Users\Kerwin\Desktop\Codes\Kerwin-Code-Study\target\classes>

# 命令含义:Prints time spent in JIT Compiler. (Introduced in 1.4.0.)
# 打印JIT编译所消耗的时间
-XX:+CITime

# 代表我指定的类
com.code.jvm.preheat.Demo

# 输出至log.txt文件,方便观看
>> log.txt

展示一下某一次结果的全部内容:

foreach time one: 35
分割线...
foreach time two: 1

Accumulated compiler times (for compiled methods only)
------------------------------------------------
  Total compilation time   :  0.044 s
    Standard compilation   :  0.041 s, Average : 0.000
    On stack replacement   :  0.003 s, Average : 0.002
    Detailed C1 Timings
       Setup time:         0.000 s ( 0.0%)
       Build IR:           0.010 s (38.8%)
         Optimize:            0.001 s ( 2.3%)
         RCE:                 0.000 s ( 0.7%)
       Emit LIR:           0.010 s (40.7%)
         LIR Gen:           0.002 s ( 9.3%)
         Linear Scan:       0.008 s (31.0%)
       LIR Schedule:       0.000 s ( 0.0%)
       Code Emission:      0.003 s (12.4%)
       Code Installation:  0.002 s ( 8.2%)
       Instruction Nodes:   9170 nodes

  Total compiled methods   :    162 methods
    Standard compilation   :    160 methods
    On stack replacement   :      2 methods
  Total compiled bytecodes :  13885 bytes
    Standard compilation   :  13539 bytes
    On stack replacement   :    346 bytes
  Average compilation speed: 312157 bytes/s

  nmethod code size        : 168352 bytes
  nmethod total size       : 276856 bytes

分别测试的结果如下:

类型Total compilation time(JIT编译总耗时)
两次 foreach(lambda) 循环0.044 s
两次 foreach (普通)循环0.016 s
两次 增强for循环0.015 s
一次 foreach(lambda) 一次增强for循环0.046 s

通过上述测试结果,反正更加说明了一个问题:只要有 Lambda 参与的程序,编译时间总会长一些

再次通过查询资料,了解了新的命令

java -verbose:class -verbose:jni -verbose:gc -XX:+PrintCompilation com.code.jvm.preheat.Demo

解释一下命令的意思

# 输出jvm载入类的相关信息
-verbose:class

# 输出native方法调用的相关情况
-verbose:jni

# 输出每次GC的相关情况
-verbose:gc

# 当一个方法被编译时打印相关信息
-XX:+PrintCompilation

对包含Lambda和不包含的分别执行命令,得到的结果如下:

从日志文件大小来看,就相差了十几kb

注:文件过大,仅展示部分内容

# 包含Lambda
[Loaded java.lang.invoke.LambdaMetafactory from D:\JDK\jre1.8\lib\rt.jar]

# 中间省略了很多内容,LambdaMetafactory 是最明显的区别(仅从名字上发现)

[Loaded java.lang.invoke.InnerClassLambdaMetafactory$1 from D:\JDK\jre1.8\lib\rt.jar]
   5143  220       4       java.lang.String::equals (81 bytes)
[Loaded java.lang.invoke.LambdaForm$MH/471910020 from java.lang.invoke.LambdaForm]
   5143  219       3       jdk.internal.org.objectweb.asm.ByteVector::<init> (13 bytes)
[Loaded java.lang.invoke.LambdaForm$MH/531885035 from java.lang.invoke.LambdaForm]
   5143  222       3       jdk.internal.org.objectweb.asm.ByteVector::putInt (74 bytes)
   5143  224       3       com.code.jvm.preheat.Demo$$Lambda$1/834600351::accept (8 bytes)
   5143  225       3       com.code.jvm.preheat.Demo::lambda$getTime$0 (6 bytes)
   5144  226       4       com.code.jvm.preheat.Demo$$Lambda$1/834600351::accept (8 bytes)
   5144  223       1       java.lang.Integer::intValue (5 bytes)
   5144  221       3       jdk.internal.org.objectweb.asm.ByteVector::putByteArray (49 bytes)
   5144  224       3       com.code.jvm.preheat.Demo$$Lambda$1/834600351::accept (8 bytes)   made not entrant
   5145  227 %     4       java.util.ArrayList::forEach @ 27 (75 bytes)
   5146    3       3       java.lang.String::equals (81 bytes)   made not entrant
foreach time one: 50
分割线...
   5147  227 %     4       java.util.ArrayList::forEach @ -2 (75 bytes)   made not entrant
foreach time two: 1
[Loaded java.lang.Shutdown from D:\JDK\jre1.8\lib\rt.jar]
[Loaded java.lang.Shutdown$Lock from D:\JDK\jre1.8\lib\rt.jar]



# 不包含Lambda
   5095   45       1       java.util.ArrayList::access$100 (5 bytes)
   5095   46       1       java.lang.Integer::intValue (5 bytes)
   5096   47       3       java.util.ArrayList$Itr::hasNext (20 bytes)
   5096   49       3       java.util.ArrayList$Itr::checkForComodification (23 bytes)
   5096   48       3       java.util.ArrayList$Itr::next (66 bytes)
   5096   50       4       java.util.ArrayList$Itr::hasNext (20 bytes)
   5096   51       4       java.util.ArrayList$Itr::checkForComodification (23 bytes)
   5096   52       4       java.util.ArrayList$Itr::next (66 bytes)
   5097   47       3       java.util.ArrayList$Itr::hasNext (20 bytes)   made not entrant
   5097   49       3       java.util.ArrayList$Itr::checkForComodification (23 bytes)   made not entrant
   5097   48       3       java.util.ArrayList$Itr::next (66 bytes)   made not entrant
   5099   53 %     4       com.code.jvm.preheat.Demo::getTimeFor @ 11 (47 bytes)
   5101   50       4       java.util.ArrayList$Itr::hasNext (20 bytes)   made not entrant
foreach time one: 7
分割线...
   5102   54       3       java.util.ArrayList$Itr::hasNext (20 bytes)
   5102   55       4       java.util.ArrayList$Itr::hasNext (20 bytes)
   5103   53 %     4       com.code.jvm.preheat.Demo::getTimeFor @ -2 (47 bytes)   made not entrant
foreach time two: 1
   5103   54       3       java.util.ArrayList$Itr::hasNext (20 bytes)   made not entrant
[Loaded java.lang.Shutdown from D:\JDK\jre1.8\lib\rt.jar]
[Loaded java.lang.Shutdown$Lock from D:\JDK\jre1.8\lib\rt.jar]

我们可以结合JIT编译时间,结合JVM载入类的日志发现两个结论:

  1. 凡是使用了Lambda,JVM会额外加载 LambdaMetafactory类,且耗时较长
  2. 在第二次调用Lambda方法时,JVM就不再需要额外加载 LambdaMetafactory类,因此执行较快

完美印证了之前提出的问题:为什么第一次 foreach 慢,以后都很快,但这就是真相吗?我们继续往下看

排除 foreach 的干扰

先来看看 ArrayList中 foreach方法的实现:

@Override
public void forEach(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    final int expectedModCount = modCount;
    @SuppressWarnings("unchecked")
    final E[] elementData = (E[]) this.elementData;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        action.accept(elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

乍一看,好像也没什么特别,我们来试试把 Consumer 预先定义好,代码如下:

可以发现速度很快,检查 JIT编译时间,检查类加载情况,发现耗时短,且无LambdaMetafactory加载

根据刚才得到的结论,我们试试把 Consumer 用 Lambda的方式定义一下

Consumer consumer = o -> {
    int curr = (int) o;
};

# 执行结果耗时
foreach time: 3

再来看看编译时间和类加载,赫然发现:JIT编译时间较长,且有LambdaMetafactory加载

重新探究Lambda的实现原理

Lambda表达式实现原理的细节,我之后会再出一篇新的文章,今天就先说一下结论:

  • 匿名内部类在编译阶段会多出一个类,而Lambda不会,它仅会多生成一个函数
  • 该函数会在运行阶段,会通过LambdaMetafactory工厂来生成一个class,进行后续的调用

为什么Lamdba要如此实现?

匿名内部类有一定的缺陷:

  1. 编译器为每个匿名内部类生成一个新的类文件,生成许多类文件是不可取的,因为每个类文件在使用之前都需要加载和验证,这会影响应用程序的启动性能,加载可能是一个昂贵的操作,包括磁盘I/O和解压缩JAR文件本身。
  2. 如果lambdas被转换为匿名内部类,那么每个lambda都有一个新的类文件。由于每个匿名内部类都将被加载,它将占用JVM的元空间,如果JVM将每个此类匿名内部类中的代码编译为机器码,那么它将存储在代码缓存中。
  3. 此外,这些匿名内部类将被实例化为单独的对象。因此,匿名内部类会增加应用程序的内存消耗。
  4. 最重要的是,从一开始就选择使用匿名内部类来实现lambdas,这将限制未来lambda实现更改的范围,以及它们根据未来JVM改进而演进的能力。

内容参考:https://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood/

真相

在理解了匿名内部类以及Lambda表达式的实现原理后,对Lambda耗时长的原因反而更懵逼,毕竟匿名内部类的生成一个新类和Lambda生成一个新方法所耗时间差别不会太多,然后运行期间同样有Class产生,耗时也不应该有太大的区别,到底哪里出现了问题呢?

再次通过查询资料,最终找到了答案:

You are obviously encountering the first-time initialization overhead of lambda expressions. As already mentioned in the comments, the classes for lambda expressions are generated at runtime rather than being loaded from your class path.

However, being generated isn’t the cause for the slowdown. After all, generating a class having a simple structure can be even faster than loading the same bytes from an external source. And the inner class has to be loaded too. But when the application hasn’t used lambda expressions before, even the framework for generating the lambda classes has to be loaded (Oracle’s current implementation uses ASM under the hood). This is the actual cause of the slowdown, loading and initialization of a dozen internally used classes, not the lambda expression itself.

大概翻译过来如下:

显然,您遇到了lambda表达式的首次初始化开销。正如注释中已经提到的,lambda表达式的类是在运行时生成的,而不是从类路径加载的。

然而,生成类并不是速度变慢的原因。毕竟,生成一个结构简单的类比从外部源加载相同的字节还要快。内部类也必须加载。但是,当应用程序以前没有使用lambda表达式时,甚至必须加载用于生成lambda类的框架(Oracle当前的实现在幕后使用ASM)。这是导致十几个内部使用的类(而不是lambda表达式本身)减速、加载和初始化的真正原因。

真相:应用程序初次使用Lambda时,必须加载用于生成Lambda类的框架,因此需要更多的编译,加载的时间

回过头去看看类加载的日志,赫然发现了ASM框架的引入:

[Loaded jdk.internal.org.objectweb.asm.ClassVisitor from F:\Java_JDK\JDK1.8\jre\lib\rt.jar]
[Loaded jdk.internal.org.objectweb.asm.ClassWriter from F:\Java_JDK\JDK1.8\jre\lib\rt.jar]
[Loaded jdk.internal.org.objectweb.asm.ByteVector from F:\Java_JDK\JDK1.8\jre\lib\rt.jar]
[Loaded jdk.internal.org.objectweb.asm.Item from F:\Java_JDK\JDK1.8\jre\lib\rt.jar]
[Loaded jdk.internal.org.objectweb.asm.MethodVisitor from F:\Java_JDK\JDK1.8\jre\lib\rt.jar]
[Loaded jdk.internal.org.objectweb.asm.MethodWriter from F:\Java_JDK\JDK1.8\jre\lib\rt.jar]
[Loaded jdk.internal.org.objectweb.asm.Type from F:\Java_JDK\JDK1.8\jre\lib\rt.jar]
[Loaded jdk.internal.org.objectweb.asm.Label from F:\Java_JDK\JDK1.8\jre\lib\rt.jar]
[Loaded jdk.internal.org.objectweb.asm.Frame from F:\Java_JDK\JDK1.8\jre\lib\rt.jar]
[Loaded jdk.internal.org.objectweb.asm.AnnotationVisitor from F:\Java_JDK\JDK1.8\jre\lib\rt.jar]
[Loaded jdk.internal.org.objectweb.asm.AnnotationWriter from F:\Java_JDK\JDK1.8\jre\lib\rt.jar]

结论

  • 导致 foreach 测试时数据不正常的罪魁祸首是:Lambda表达式
  • Lambda表达式 在应用程序中首次使用时,需要额外加载ASM框架,因此需要更多的编译,加载的时间
  • Lambda表达式的底层实现并非匿名内部类的语法糖,而是其优化版
  • foreach 的底层实现其实和增强 for循环没有本质区别,一个是外部迭代器,一个是内部迭代器而已
  • 通过 foreach + Lambda 的写法,效率并不低,只不过需要提前进行预热(加载框架)
深入解析Lambda表达式初次使用耗时慢的问题 问题回顾 描述的话不多说,直接上图: 看到输出结果了吗?为什么第一次和第二次的时间相差如此之多?咱们一起琢磨琢磨,也可以先去看看结论再回过头看分析 注:并非仅第二次快,而是除了第一次,之后的每一次都很快 给与猜想 是否和操作系统预热有关? 是否和JIT(即时编译)有关? 是否和ClassLoader类加载有关? 是否和Lambda有关,并非foreach的问题 验证猜想 操作系统预热 操作系统预热这个概念是我咨询一位大佬得到的结论,在百度 / Google 中并未搜索到相应的词汇,但是在模拟测试中 阅读详情

相关推荐

切比雪夫插值

切比雪夫插值是一种基于切比雪夫节点的多项式插值方法,其优势是减少插值误差(特别是龙格现象:表现为高维插值时在边缘处插值误差骤增)。本文对其基本操作进行说明。

平和少年的博客 1647

Java编译过程、JIT编译详解、类加载过程

Java程序员必知的Java编译流程、JIT编译

在路上 2257

基恩士数字光纤放大器

在2路输出类型上此为通道开关,并未配备0路类型;设置已搞不清楚不知道怎么办时···完成初始化后,模块重新显示当前值。①无工件时短按[SET]①有工件时短按[SET]各部位的名称和基本操作。可以手动微调设置值。

大小曲奇的博客 1万+

Android技术前线 java8之lambda预热

google对java的支持是比较滞后的,一直到Api21才开始支持java7。在java8推出两年之后,google终于在Android N也就是Android7.x中支持java8了。作为商业项目,现在使用Android N显然为时过早,但是毕竟这是趋势,早晚要用上的,需要提前学习。

wl549388372的博客 758

使用Dify搭建音频文件转文本工作流

使用Dify搭建音频文件转文本工作流

zyx_bx的博客 5624

TC8:SOMEIPSRV_SD_MESSAGE_07-09

TTL为服务实例的生命周期。在此生命周期之后,不提供服务实例。

jasonj333 908

懒加载的原理及实现_Lambda初次使用很慢?从JIT到类加载再到实现原理,研究到底!...

问题回顾描述的话不多说,直接上图:看到输出结果了吗?为什么第一次和第二次的时间相差如此之多?咱们一起琢磨琢磨,也可以先去看看结论再回过头看分析注:并非仅第二次快,而是除了第一次,之后的每一次都很快给与猜想是否和操作系统预热有关?是否和JIT(即时编译)有关?是否和ClassLoader类加载有关?是否和Lambda有关,并非foreach的问题Tom猫的java屋​zhuanlan.zhihu.c...

weixin_39646658的博客 340

把开源 Skills 集成到 LangGraph 项目

1. 定义智能体状态(必须包含 messages,其他字段按需扩展)messages: List[HumanMessage | AIMessage | ToolMessage] # 消息流(核心)skill_output: Optional[str] # 存储 Skill 执行结果next_node: str # 控制流程跳转# 2. 定义智能体决策节点(决定是否调用 Skill)"""智能体决策逻辑:根据用户输入判断是否调用开源 Skill"""# 获取最后一条用户消息。

lpfasd123的博客 904

Lambda首次使用很慢怎么办?看法宝

描述的话不多说,直接上图: 看到输出结果了吗?为什么第一次和第二次的时间相差如此之多?咱们一起琢磨琢磨,也可以先去看看结论再回过头看分析 注:并非仅第二次快,而是除了第一次,之后的每一次都很快 给与猜想 是否和操作系统预热有关? 是否和JIT(即时编译)有关? 是否和ClassLoader类加载有关? 是否和Lambda有关,并非foreach的问题 验证猜想 操作系统预热 操作系统预热这个概念是我咨询一位大佬得到的结论,在百度 / Google 中并未搜索到相应的词汇,但是在

uuuyy_的博客 270

安装Codex时出现无法下载此应用和Microsoft Store初始化失败的解决方案

本文主要介绍了安装Codex时出现无法下载此应用和Microsoft Store初始化失败的解决方案,希望能对使用codex的同学们有所帮助。 文章目录 1. 问题描述 2. Windows 解决方案 3. Mac解决方案

weixin_43178406的博客 7万+

【雕爷学编程】Arduino动手做(75)---TTL转RS-485模块之二线制可以实现真正的多点双向通信

37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)与否,都会记录下来---小小的进步或是搞不掂的问题,希望能够抛砖引玉。 【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程) 实验七十五:TTL转RS-485模块 MAX485 RS485模块 MAX485 是一个8.

雕爷学编程 1万+

java中的lambda表达式实现原理,为什么它会显著提高性能,进来看看,必能豁然开朗

Java Lambda表达式是Java 8引入的一个重要特性,它允许将功能作为参数传递给方法或将代码作为数据处理。这种表达式简化了代码的编写,使得Java的编程风格更加函数式Java Lambda表达式通过编译时转换、运行时动态类生成和JIT优化,实现了高效的函数式编程支持。这种机制不仅简化了代码编写,还显著提升了程序的可读性和性能。

u013531166的博客 1082

我的PCB设计经验总结及最容易犯错的100例之二B07

本文总结了PCB设计中的常见错误及解决方法。作者通过记录自身及他人的设计失误,系统归纳了高频、隐蔽且致命的问题,如电容中间穿线、高速信号跨分割、锐角布线等。重点提出从错误中提炼规律,建立分类案例库,并开发自动化检查工具的方法。案例涵盖高速信号处理、电源设计、EMC防护等关键领域,强调通过原理理解和实践验证提升设计质量。文章建议工程师建立个人错误数据库,从被动纠错升级为主动预防,最终形成系统化的设计方法论,提高PCB一次成功率。

启芯硬件的博客 87

Lambda表达式性能陷阱:避坑指南与JIT编译优化分析

场景性能建议非捕获Lambda,单次调用零开销(JIT内联)放心使用非捕获Lambda,循环内调用接近零开销放心使用捕获Lambda,循环内调用每次有对象分配关注,但通常可接受Stream 单操作低开销数据量>1000时性能良好Stream 多操作链中开销JIT优化后接近手写循环并行Stream(数据量小)高开销避免并行Stream(数据量大)可能提升2-8x需测试Lambda 捕获可变变量编译错误必须用final或等效final。

开发小能手-Haha king的博客 191

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

专家视角看Lambda表达式的原理解析

摘要:Lambda表达式使用invokedynamic指令提供的高级特效实现,其核心是将创建逻辑推迟到运行时处理。编译时生成invokedynamic指向LambdaMetafactory.metafactory方法,运行时通过InnerClassLambdaMetafactory动态生成实现类字节码。整个过程包含:1)编译期埋入invokedynamic指令;2)运行时通过BSM引导;3)动态生成Lambda类;4)JIT优化执行路径。这种延迟绑定机制实现了Lambda的高效运行,同时保持字节码兼容性。

wuminyu的博客 813

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

JIT耗时优化

业务流量突增,机器直接接入大量流量,和会消耗太多资源,导致1-2分钟时间内的请求超时导致异常,因此采用流量预热的方式,让机器逐步接入流量,需要预热时长。目前服务接入,通过自动扩缩容应用流量变化,当流量激增时,对机器的启动速度带来了挑战,之前通过优化点火时间,已经将机器从容器创建到可接入流量优化到2分钟左右,但3min的预热时长成为了应对流量激增的瓶颈,因此优化机器从接入流量到能稳定服务的时长,目标缩减到2min以内。什么是服务预热: 应用在刚启动的时候处理相应速度会很慢,只有当热点代码执行了一定次数以后,相

程序猿进阶 1784

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

字节码之 Lambda 表达式底层原理

前两章我们了解了JVM之所以夸平台的一个重要特性,字节码指令、并且通过javap反编译了一些常见的java 语句的字节码指令,了解了之所以这些语句举报那样的特性。今天我们从字节码指令层面聊聊Lambda表达式的底层原理。首先我们写一个简单的lambda表达式,并用javap命令反编译成字节码指令。(动态方法调用)是Java 7引入的一个新的字节码指令,目的是为了支持动态类型语言在Java平台上的执行。这个指令特别适用于执行那些在编译时类型未知的方法调用。在Lambda表达式中,

日拱一卒无有尽,功不唐捐终入海 792
上一篇: 腾讯大战老干妈,到底是谁输了呢?我笑疯了!
下一篇: 为什么老外不愿意用 MyBatis?
Java技术那些事儿
博客等级 码龄5年 2306粉丝 2584原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值