Java:不带变量的实例的性能
我上过这样的课:Java:不带变量的实例的性能,java,performance,Java,Performance,我上过这样的课: class Test { public static test getInstance() { return new test() } public void firstMethod() { //do something } public void secondMethod() { //do something } public void third
class Test
{
public static test getInstance()
{
return new test()
}
public void firstMethod()
{
//do something
}
public void secondMethod()
{
//do something
}
public void thirdMethod()
{
//do something
}
}
在另一个类中,如果我们使用不同的方法多次调用Test.getInstance().methodName()
,会发生什么?
在以下代码中,哪一个速度更快且内存较低
Test.getInstance().firstMethod()
Test.getInstance().secondMethod()
Test.getInstance().thirdMethod()
或
这将创建Test
类的三个不同实例,并对每个实例调用一个方法
Test test = Test.getInstance();
test.firstMethod();
test.secondMethod();
test.thirdMethod();
将仅创建一个实例并在该实例上调用三个方法
所以这是一个完全不同的行为开始。显然,因为第一个创建了三个对象,所以它应该占用更多的堆空间
但是,如果您打算实现一个单例类,那么这两个类是等价的
这将创建Test
类的三个不同实例,并对每个实例调用一个方法
Test test = Test.getInstance();
test.firstMethod();
test.secondMethod();
test.thirdMethod();
将仅创建一个实例并在该实例上调用三个方法
所以这是一个完全不同的行为开始。显然,因为第一个创建了三个对象,所以它应该占用更多的堆空间
但是,如果您打算实现一个单例类,那么这两个类是等效的。每次调用
getInstance
时,系统都必须为测试
对象分配堆存储并对其进行初始化
此外,在接下来的某个地方,系统将不得不对所有这些额外的
Test
对象进行垃圾收集。使用复制收集器,每个对象的开销是最小的,但也有一些开销——如果不是因为其他原因,而是因为您导致GC更频繁地发生。每次调用getInstance
时,系统都必须为测试
对象分配堆存储并对其进行初始化
class Test
{
public static Test getInstance()
{
return new Test();
}
public void firstMethod()
{
// do something
}
public void secondMethod()
{
// do something
}
public void thirdMethod()
{
// do something
}
}
public class Blah
{
public static void main(String[] args)
{
int i = 0;
long start = System.nanoTime();
Test t = new Test();
for (; i < 100000; i++)
{
t.firstMethod();
}
long stop = System.nanoTime();
System.out.println(stop - start);
i = 0;
start = System.nanoTime();
for (; i < 100000; i++)
{
Test.getInstance().firstMethod();
}
stop = System.nanoTime();
System.out.println(stop - start);
}
}
此外,在接下来的某个地方,系统将不得不对所有这些额外的Test
对象进行垃圾收集。使用复制收集器,每个对象的开销是最小的,但也有一些——如果不是因为其他原因,就是因为您导致GC更频繁地发生的话
class Test
{
public static Test getInstance()
{
return new Test();
}
public void firstMethod()
{
// do something
}
public void secondMethod()
{
// do something
}
public void thirdMethod()
{
// do something
}
}
public class Blah
{
public static void main(String[] args)
{
int i = 0;
long start = System.nanoTime();
Test t = new Test();
for (; i < 100000; i++)
{
t.firstMethod();
}
long stop = System.nanoTime();
System.out.println(stop - start);
i = 0;
start = System.nanoTime();
for (; i < 100000; i++)
{
Test.getInstance().firstMethod();
}
stop = System.nanoTime();
System.out.println(stop - start);
}
}
使用new Test()创建单个实例的速度持续提高了约30%
由于无法在一次运行中完成内存计算,因此内存计算更加困难。但是,如果我们只运行第一个循环(更改内部内容)并使用:
就在印刷之前。在两次单独的运行中,我们可以确定差异:newtest()
的~671200
或~1342472
(似乎在运行之间随机变化,对运行时没有明显影响)和getInstance()
的~2389288
(这次没有大的差异)在100000次迭代中。再次明确胜利的单一实例
使用new Test()创建单个实例的速度持续提高了约30%
由于无法在一次运行中完成内存计算,因此内存计算更加困难。但是,如果我们只运行第一个循环(更改内部内容)并使用:
就在印刷之前。在两次单独的运行中,我们可以确定差异:
newtest()
的~671200
或~1342472
(似乎在运行之间随机变化,对运行时没有明显影响)和getInstance()
的~2389288
(这次没有大的差异)在100000次迭代中。再次明确的单实例胜利@GáborBakos证明了itI不认为它会是任何的-它应该是相同的-原因是编译器优化了它。在一天结束时,所有东西都在Java的堆空间中,垃圾收集会丢弃你没有用完的东西。在第一个实例中唯一不同的是Test.getInstance().firstMethod()等的引用计数。只有一个测试对象。我想肯定有人会把它放在他/她的答案中解释。我认为第二个更快,因为第一个会为每个方法调用创建一个新实例,对吗?除非它得到优化。当您使用getInstance()
方法时,通常意味着您使用,这意味着只有第一个调用将创建一个新测试
,并且所有后续调用都返回该实例。当您有一个应该在每次调用时返回新实例的时,请调用它create()
或makeTest()
。另外,当类的方法不使用任何变量时,您应该将它们设置为静态
,并使用Test.methodName
静态调用它们。请参阅下面的注释@Chris。所有对象都至少是对象
的一个实例,它必须分配内存。这确实需要时间。@GáborBakos证明了这一点,我认为它不会有任何变化——它应该是相同的——原因是编译器无论如何都会对它进行优化。在一天结束时,所有东西都在Java的堆空间中,垃圾收集会丢弃你没有用完的东西。在第一个实例中唯一不同的是Test.getInstance().firstMethod()等的引用计数。只有一个测试对象。我想肯定有人会把它放在他/她的答案中解释。我认为第二个更快,因为第一个会为每个方法调用创建一个新实例,对吗?除非它得到优化。当您使用getInstance()
方法时,通常意味着您使用,这意味着只有第一个调用将创建一个新测试
,并且所有后续调用都返回该实例。当您有一个应该在每次调用时返回新实例的时,请调用它create()
或makeTest()
。另外,当类的方法不使用任何变量时,您应该将它们设置为静态
,并使用Test.methodName
静态调用它们。请参阅下面的注释@Chris。所有对象都至少是对象
的一个实例,它必须分配内存。这确实需要时间。而且由于每个对象都是对象
,JIT可能无法完全优化对new
的调用。因此,必须分配内存(以
~3486938
~4894574
Runtime runtime = Runtime.getRuntime();
long memory = runtime.totalMemory() - runtime.freeMemory();