for循环条件中方法调用的效率
Efficiency of method call in for loop condition
我正在编写一个游戏引擎,其中 ArrayList
中的一组对象使用 for 循环进行迭代。显然,效率很重要,所以我想知道循环的效率。
for (String extension : assetLoader.getSupportedExtensions()) {
// do stuff with the extension here
}
其中 getSupportedExtension()
returns ArrayList
个 String
。我想知道的是,每次循环迭代新扩展时是否调用该方法。如果是这样,做这样的事情会更有效率吗:
ArrayList<String> supportedExtensions = ((IAssetLoader<?>) loader).getSupportedExtensions();
for (String extension : supportedExtensions) {
// stuff
}
?提前致谢。
不,方法 assetLoader.getSupportedExtensions()
在循环的第一次迭代之前只被调用一次,用于创建增强的 for 循环使用的 Iterator<String>
。
这两个片段将具有相同的性能。
根据规范,成语
for (String extension : assetLoader.getSupportedExtensions()) {
...
}
扩展为
for (Iterator<String> it = assetLoader.getSupportedExtensions().iterator(); it.hasNext();)
{
String extension = it.next();
...
}
因此,您询问的调用只发生一次,在循环初始化时。它是迭代器对象,其方法被重复调用。
但是,如果您真的对应用程序的性能感兴趣,那么您应该确保您关注的是大赢家,而不是像这样的小人物。几乎不可能使 getter 调用成为任何代码段中的瓶颈。这对于 HotSpot 上的应用程序 运行 来说是双倍的,它将内联 getter 调用并将其转换为直接字段访问。
- 直接成本。
因为,正如人们之前所说,以下
for (String extension : assetLoader.getSupportedExtensions()) {
//stuff
}
变身
for (Iterator<String> it = assetLoader.getSupportedExtensions().iterator(); it.hasNext();) {
String extension = it.next();
//stuf
}
getSupportedExtensions() 被调用一次,您的两个代码片段具有相同的性能成本,但不是通过列表的最佳性能,因为...
- 间接成本
这是实例化和使用新的短期对象的成本 + 方法 next() 的成本。方法 iterator() 准备 Iterator 的实例。因此,需要花时间实例化对象,然后(当该对象变得不可访问时)对其进行 GC。总的间接成本不是 so 很多(大约 10 条指令为新对象分配内存 + 一些构造函数指令 + 大约 5 行 ArrayList.Itr.next() + 删除来自 Eden 的次要 GC 上的对象),但我个人更喜欢索引(甚至是普通数组):
ArrayList<String> supportedExtensions = ((IAssetLoader<?>) loader).getSupportedExtensions();
for (int i = 0; i < supportedExtensions.size(); i++) {
String extension = supportedExtensions.get(i);
// stuff
}
当我必须在我的应用程序的主路径中频繁地遍历列表时,过度迭代。具有隐藏成本的标准 java 代码的其他一些示例是一些字符串方法(substring()、trim() 等)、NIO 选择器、将它们存储在集合中的原语 boxing/unboxing 等.
我正在编写一个游戏引擎,其中 ArrayList
中的一组对象使用 for 循环进行迭代。显然,效率很重要,所以我想知道循环的效率。
for (String extension : assetLoader.getSupportedExtensions()) {
// do stuff with the extension here
}
其中 getSupportedExtension()
returns ArrayList
个 String
。我想知道的是,每次循环迭代新扩展时是否调用该方法。如果是这样,做这样的事情会更有效率吗:
ArrayList<String> supportedExtensions = ((IAssetLoader<?>) loader).getSupportedExtensions();
for (String extension : supportedExtensions) {
// stuff
}
?提前致谢。
不,方法 assetLoader.getSupportedExtensions()
在循环的第一次迭代之前只被调用一次,用于创建增强的 for 循环使用的 Iterator<String>
。
这两个片段将具有相同的性能。
根据规范,成语
for (String extension : assetLoader.getSupportedExtensions()) {
...
}
扩展为
for (Iterator<String> it = assetLoader.getSupportedExtensions().iterator(); it.hasNext();)
{
String extension = it.next();
...
}
因此,您询问的调用只发生一次,在循环初始化时。它是迭代器对象,其方法被重复调用。
但是,如果您真的对应用程序的性能感兴趣,那么您应该确保您关注的是大赢家,而不是像这样的小人物。几乎不可能使 getter 调用成为任何代码段中的瓶颈。这对于 HotSpot 上的应用程序 运行 来说是双倍的,它将内联 getter 调用并将其转换为直接字段访问。
- 直接成本。
因为,正如人们之前所说,以下
for (String extension : assetLoader.getSupportedExtensions()) {
//stuff
}
变身
for (Iterator<String> it = assetLoader.getSupportedExtensions().iterator(); it.hasNext();) {
String extension = it.next();
//stuf
}
getSupportedExtensions() 被调用一次,您的两个代码片段具有相同的性能成本,但不是通过列表的最佳性能,因为...
- 间接成本
这是实例化和使用新的短期对象的成本 + 方法 next() 的成本。方法 iterator() 准备 Iterator 的实例。因此,需要花时间实例化对象,然后(当该对象变得不可访问时)对其进行 GC。总的间接成本不是 so 很多(大约 10 条指令为新对象分配内存 + 一些构造函数指令 + 大约 5 行 ArrayList.Itr.next() + 删除来自 Eden 的次要 GC 上的对象),但我个人更喜欢索引(甚至是普通数组):
ArrayList<String> supportedExtensions = ((IAssetLoader<?>) loader).getSupportedExtensions();
for (int i = 0; i < supportedExtensions.size(); i++) {
String extension = supportedExtensions.get(i);
// stuff
}
当我必须在我的应用程序的主路径中频繁地遍历列表时,过度迭代。具有隐藏成本的标准 java 代码的其他一些示例是一些字符串方法(substring()、trim() 等)、NIO 选择器、将它们存储在集合中的原语 boxing/unboxing 等.