注册 登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

为着理想勇敢前进

 
 
 

日志

 
 

大量new临时对象可以是一种优化手段  

2012-02-29 08:24:23|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

有C++经验的人往往知道,频繁在堆上分配对象对性能伤害很大。比如这样的代码就不是好代码:

void foo(int[] a) {
WrappedArray* wrappedArray = new WrappedArray(a);
wrappedArray->bar();
delete wrappedArray;
}

然而在JVM(指HotSpot虚拟机)上完全不是这样的。尽管JVM不提供显式在栈上创建对象的功能,但JVM会自动通过逃逸分析找出生命周期在函数范围内的临时对象,然后运行时优化这个函数,把对象创建放到栈上。逃逸分析在JRE7里面已经默认开启了,对临时对象多的代码效果很大。

Scala的隐式类型转换特性很鼓励创建临时对象。标准库中就有大量的隐式转换,会生成许多临时对象,如WrappedArrayStringAddWithFilter等。我读标准库的源码时甚至感到他们已经把创建临时对象当成一种优化手段了。

比如C++常见的pimpl模式往往会让用户代码持有一个包装对象的指针,包装对象的内部有一个底层实现对象的指针。这种做法在Scala里面就完全不被主张,而更鼓励长期持有底层对象,而在需要用时再临时包装成对外接口。

Scala的Array对应Java中的数组,功能很少,但Array可以隐式转换为功能全面的ArrayOps,使用ArrayOps上的函数时会生成多个临时对象。试看如下代码:

val myArray = Array("foo", "bar", "baz")
for (element <- myArray if element.contains('a')) { println(element) }

Scala编译器会把上述代码转换成这样:

val myArray: Array[String] = Array.apply("foo", "bar", "baz")
new (new ArrayOps[String](myArray)).WithFilter(
new AbstractFunction1[String, Boolean] {
override def apply(element: String): Boolean = {
return new StringOps(element).contains('a')
}
}).foreach(new AbstractFunction1[String, Unit] {
override def apply(element: String) {
println(element)
}
})

颤抖吧骚年,这一小段代码中居然有五处new,创建了ArrayOps[String]ArrayOps[String]#WithFilterAbstractFunction1[String, Boolean]StringOpsAbstractFunction1[String, Unit]整整五个临时对象。

Scala宁愿创建这么多临时对象也不用pimp模式是因为pimpl模式比直接持有底层对象多保存一个包装对象。如果在容器中保存大量包装对象时,额外的内存开销就会多起来,而pimp模式还会导致每次函数调用也多一次间接寻址的开销。另一方面,只持有底层对象的话,虽然原则上每次使用都会生成临时对象,但是这些临时对象经过JVM的逃逸分析、标量替换和内联优化后是零开销的。

但临时对象的开销取决于JVM的优化,然而JVM要在运行时优化,而且只有频繁运行的代码才会被优化。所以如果一个程序创建很多临时对象,那么刚启动时它的性能会很差,而运行一段时间后会慢慢变好。这也是为什么我们经常会感觉Java程序启动慢的原因之一。

  评论这张
 
阅读(1301)| 评论(5)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018