包装对象的实际开销是多少?

时间:2013-09-29 22:59:53

标签: java performance creation overhead

我有一个时间敏感的应用程序,可以从第三方库获取数据。将我们的对象包装到我的应用程序的更合适的接口中会产生什么样的性能影响?

注意:我在这里发布答案(Q& A风格),但如果错了请纠正我!

2 个答案:

答案 0 :(得分:1)

间接有一些开销,但很难衡量。 OP的基准测试每次迭代大约需要4 ns,而我的需要大约1 ns(对于最快的实验)。这意味着他们主要测量ArrayListIteratorcycle的开销,可能还有虚拟呼叫开销。

要测量的开销非常小,您需要使用数组并添加内部循环或使用掩码来访问它们。

resultsbenchmark表明使用接口和间接都有可测量的开销。这种开销可能在20%到50%之间,看起来很多。但是,重要的部分是的20-50%。这只是特制基准测试的一小部分,除了执行代码之外什么都不做。在任何现实的片段代码中,相对开销将低十,百或千倍。

因此,除非您正在设计一个执行一些非常基本和快速操作的高性能库,否则请忘记它。随意使用间接和接口,专注于良好的设计。即使表现很重要,也可能有其他地方可以获得更多。

WrappingBenchmark

答案 1 :(得分:0)

在尝试使用他们的课程数月之后,今天我决定进行测试。似乎任何开销都不会增加太多。以下是结果 - 实际上并非完全一致,这里有一个实际上已解开的是SLOWER:

 0% Scenario{vm=java, trial=0, benchmark=Unwrapped} 3.96 ns; ?=0.02 ns @ 3 trials
33% Scenario{vm=java, trial=0, benchmark=Copy} 3.93 ns; ?=0.01 ns @ 3 trials
67% Scenario{vm=java, trial=0, benchmark=Backing} 3.94 ns; ?=0.01 ns @ 3 trials

benchmark   ns linear runtime
Unwrapped 3.96 ==============================
     Copy 3.93 =============================
  Backing 3.94 =============================

vm: java
trial: 0

源代码(Caliper 0.5-rc1,Guava 2.0 +):

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;
import com.google.common.collect.Iterables;

public class WrapperTest {
    public static class Unwrapped {
        private int inner;

        public Unwrapped(int inner) {
            this.inner = inner;
        }

        public int getInner() {
            return inner;
        }
    }

    public static interface Outer {
        public int getOuter();
    }

    public static class CopyOuter implements Outer {
        private int outer;

        public CopyOuter(int outer) {
            this.outer = outer;
        }

        public int getOuter() {
            return outer;
        }
    }

    public static class BackingOuter implements Outer {
        private Unwrapped inner;

        public BackingOuter(Unwrapped inner) {
            this.inner = inner;
        }

        public int getOuter() {
            return inner.getInner();
        }
    }

    public static class TestBenchmark extends SimpleBenchmark {
        private Iterable<Unwrapped> cycle;

        @Override
        protected void setUp() {
            List<Unwrapped> backing = new ArrayList<Unwrapped>(16384);
            Random r = new Random();
            for(int i = 0; i < 16384; i++) {
                backing.add(new Unwrapped(Math.abs(r.nextInt())));
            }
            cycle = Iterables.cycle(backing);
        }

        public long timeUnwrapped(int reps) {
            long total = 0;
            Iterator<Unwrapped> iter = cycle.iterator();
            for(int i = 0; i < reps; i++) {
                total += iter.next().getInner();
            }
            return total;
        }

        public long timeCopy(int reps) {
            long total = 0;
            Iterator<Unwrapped> iter = cycle.iterator();
            for(int i = 0; i < reps; i++) {
                total += new CopyOuter(iter.next().getInner()).getOuter();
            }
            return total;
        }

        public long timeBacking(int reps) {
            long total = 0;
            Iterator<Unwrapped> iter = cycle.iterator();
            for(int i = 0; i < reps; i++) {
                total += new BackingOuter(iter.next()).getOuter();
            }
            return total;
        }
    }

    public static void main(String[] args) {
        Runner.main(TestBenchmark.class, new String[0]);
    }
}