Kotlin内存陷阱inline使用技巧示例详解

 更新时间:2022年10月14日 11:02:55   作者:Petterp  
这篇文章主要为大家介绍了Kotlin内存陷阱inline使用技巧示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

inline ,翻译过来为 内联 ,在 Kotlin 中,一般建议用于 高阶函数 中,目的是用来弥补其运行时的 额外开销。

其原理也比较简单,在调用时将我们的代码移动到调用处使用,从而降低方法调用时的 栈帧 层级。

栈帧: 指的是虚拟机在进行方法调用和方法执行时的数据结构,每一个栈帧里都包含了相应的数据,比如 局部参数,操作数栈等等。

Jvm在执行方法时,每执行一个方法会产生一个栈帧,随后将其保存到我们当前线程所对应的栈里,方法执行完毕时再将此方法出栈,

所以内联后就相当于省了一个栈帧调用。

如果上述描述中,你只记住了后半句,降低栈帧 ,那么此时你可能已经陷入了一个使用陷阱?

错误示例

如下截图中所示,我们随便创建了一个方法,并增加了 inline 关键字:

观察截图会发现,此时IDE已经给出了提示,它建议你移除 inline , Why? 为什么呢?🥲

不是说内联可以提高性能吗,那么不应该任何方法都应该加 inline 提高性能吗?(就是这么倔强🤌🏼)

上面我们提到了,内联是会将代码移动到调用处,降低 一层栈帧,但这个性能提升真的大吗?

再仔细想想,移动到调用处,移动到调用处。这是什么概念呢?

假设我们某个方法里代码只有两行(我想不会有人会某个方法只有一行吧🥲),这个方法又被好几处调用,内联是提高了调用性能,毕竟节省了一次栈帧,再加上方法行数少(暂时抛弃虚拟机优化这个底层条件)。

但如果方法里代码有几十行?每次调用都会把代码内联过来,那调用处岂不💥,带来的包大小影响某种程度上要比内联成本更高😵‍💫!

如下图所示,我们对上述示例做一个论证:

Jvm: 我谢谢你。

推荐示例

我们在文章最开始提到了,Kotlin inline ,一般建议用于 高阶函数(lambda) 中。为什么呢?

如下示例:

转成字节码后,可以发现,tryKtx() 被创建为了一个匿名内部类 (Simple$test|1) 。每次调用时,相当于需要创建匿名类的实例对象,从而导致二次调用的性能损耗。

那如果我们给其增加 inline 呢?🤖,反编译后相应的 java代码 如下:

具体对比图如上所示,不难发现,我们的调用处已经被替换为原方法,相应的 lambda 也被消除了,从而显著减少了性能损耗。

小结

如果查看官方库相应的代码,如下所示,比如 with :

public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

不难发现,inline 的大多数场景仅且在 高阶函数 并且 方法行数较短 时适用。因为对于普通方法,jvm本身对其就会进行优化,所以 inline 在普通方法上的的意义几乎聊胜于无。

总结

  • 因为内联函数会将方法函数移动到调用处,会增加调用处的代码量,所以对于较长的方法应该避免使用;
  • 内联函数应该用于使用了 高阶函数(lambda) 的方法,而不是普通方法。

以上就是Kotlin内存陷阱inline使用技巧示例详解的详细内容,更多关于Kotlin内存陷阱inline使用的资料请关注脚本之家其它相关文章!

相关文章

  • javax.validation包里@NotNull等注解的使用方式

    javax.validation包里@NotNull等注解的使用方式

    这篇文章主要介绍了javax.validation包里@NotNull等注解的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • 如何解决SpringBoot定时任务报错Unexpected error occurred in scheduled task问题

    如何解决SpringBoot定时任务报错Unexpected error occurred 

    这篇文章主要介绍了如何解决SpringBoot定时任务报错Unexpected error occurred in scheduled task问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • java 利用反射获取内部类静态成员变量的值操作

    java 利用反射获取内部类静态成员变量的值操作

    这篇文章主要介绍了java 利用反射获取内部类静态成员变量的值操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • maven中添加memcached.jar的配置步骤

    maven中添加memcached.jar的配置步骤

    在Java项目中使用Maven管理依赖时,如果需要添加​​memcached.jar​​依赖,可以通过本文介绍的步骤进行配置,文章通过代码示例讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-12-12
  • JAVA日志框架之JUL、JDK原生日志框架详解

    JAVA日志框架之JUL、JDK原生日志框架详解

    Java语言的强大之处就是因为它强大而且成熟的生态体系,其中包括日志框架,下面这篇文章主要给大家介绍了关于JAVA日志框架之JUL、JDK原生日志框架的相关资料,需要的朋友可以参考下
    2024-01-01
  • 关于JVM默认堆内存大小问题

    关于JVM默认堆内存大小问题

    这篇文章主要介绍了关于JVM默认堆内存大小问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Java中Spring获取bean方法小结

    Java中Spring获取bean方法小结

    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,如何在程序中获取Spring配置的bean呢?下面通过本文给大家介绍Java中Spring获取bean方法小结,对spring获取bean方法相关知识感兴趣的朋友一起学习吧
    2016-01-01
  • 解决IntelliJ IDEA输出中文显示为问号问题的有效方法

    解决IntelliJ IDEA输出中文显示为问号问题的有效方法

    最近刚学到文件字节流这里,但输出中文时,出现了控制台输出问号的情况,所以下面这篇文章主要给大家介绍了关于如何解决IntelliJ IDEA输出中文显示为问号问题的有效方法,需要的朋友可以参考下
    2022-07-07
  • maven 打包项目的几种方式

    maven 打包项目的几种方式

    maven目前在web上面的使用方式很普遍,而打包的方式也存在很多方式,本文就详细的介绍了三种方式,具有一定的参考价值,感兴趣的可以了解下
    2021-06-06
  • Scala常用List列表操作方法示例

    Scala常用List列表操作方法示例

    这篇文章主要介绍了Scala常用List列表操作方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-06-06

最新评论