Kotlin中为何为变量使用inline关键字?相关内联疑问解析
为什么loggingTag内联属性要加inline?
这个泛型扩展属性标记inline,关键原因有两个:
消除属性访问的方法调用开销:普通属性的getter会被编译成独立方法,每次访问都得走一次函数调用流程。而内联属性的getter会直接被展开到调用它的代码位置,彻底去掉这层调用的栈帧开销——对于日志这种可能被频繁调用的场景,这点开销的累积不容忽视。
配合
reified泛型的内联函数高效工作:这个属性被用在带reified T的errorLog扩展函数里。当内联属性的getter被内联到扩展函数后,this::class.java能直接拿到调用点的具体类型Class对象——因为reified泛型已经把具体类型信息带到了调用现场,内联后的代码不需要通过反射或者额外类型传递来获取Class,保证了类型获取的高效性。
另外,@PublishedApi和internal搭配是必要的:内联函数的代码会被复制到调用方的代码中,如果这个属性是internal的,默认调用方无法访问。@PublishedApi的作用就是允许这个内部属性在被内联展开后,能被调用方代码正常访问,避免编译报错。
为什么无函数参数的errorLog也要加inline?
这个顶层errorLog标记inline,核心是消除整个调用链的函数调用开销:
它被前面带
reified的inline扩展函数调用。如果这个顶层函数不inline,哪怕扩展函数被内联了,最后还是会产生一次对errorLog(tag, ...)的函数调用。把它也标记为inline后,整个调用链(扩展函数→顶层函数→Timber调用)会被完全展开到调用点,相当于直接写Timber.tag(xxx).e(...),完全没有额外的函数调用开销。日志属于高频调用的工具函数,哪怕是一次微小的函数调用开销,在大量调用场景下也会累积出性能差异。内联后能让日志代码的执行效率接近直接调用Timber的原生代码。
内容的提问来源于stack exchange,提问作者Omar Redani

