返回新对象时的Java内存管理

时间:2015-07-02 10:25:51

标签: java memory-management

我想知道更好的内存管理编码方式,

方法1:

Obj temp;
public static Obj fun1() {
      ......
      ......
      Obj temp = new Obj();
      return temp;
}

方法2:

public static Obj fun1() {
     ........
     .........
     return new Obj;
}

哪种方法会好?两种方法都做同样的工作。但是第二种方法返回创建新的Object,而第一种方法create Object将其存储在变量中并返回变量。

请考虑我的函数将返回大量此类函数返回不同类的Object。并且在执行自动测试程序期间会多次调用它们。我应该使用哪一个?为什么?

6 个答案:

答案 0 :(得分:2)

使用单例模式。如果可以跨越相同的实例,则创建一次静态对象 它就像

static Object temp;
public Object getObjectInstance(){
if(temp==null){
temp = new Object();
}

return temp; 
}

答案 1 :(得分:0)

两种方式都可以,并且对内存产生同样的影响。如果要在返回函数之前对函数内部的对象执行某些操作,则使用第一个。第二个假设您不想这样做。

答案 2 :(得分:0)

回答:您指定的两种方法存在非常小的差异。您也知道,在这两种方法中都会创建一个新对象,因此适合您。现在您担心在第二种方法中将使用一个新变量来存储对象引用 - 但它确实无关紧要,因为只要方法结​​束,该方法创建的所有局部变量都将从堆栈中删除。

<强>概念

  • 对象存在于内存区域的堆中。
  • 变量存在于堆栈中,一旦方法完成,该方法创建的所有局部变量都将从堆栈中删除。

简而言之:对于您提供的方法,在内存管理方面几乎没有任何差异。

答案 3 :(得分:0)

字节码中存在实际差异。我们来看下面的课程。

public class Test {
    public static void main(String... args) {
        final int LIMIT = 10_000_000;
        final int RUNS = 10;
        for (int run = 0; run < RUNS; ++run) {
            Test[] t = new Test[LIMIT];
            long start = System.nanoTime();
            for (int i = 0; i < LIMIT; ++i) {
                t[i] = fun1();
            }

            System.out.println(  "fun1: "
                               + ((System.nanoTime() - start) / 1_000_000_000d)
                               + "s");

            t = new Test[LIMIT];
            start = System.nanoTime();
            for (int i = 0; i < LIMIT; ++i) {
                t[i] = fun2();
            }

            System.out.println(  "fun2: "
                               + ((System.nanoTime() - start) / 1_000_000_000d)
                               + "s");

        }
    }

    public static Test fun1() {
        return (new Test());
    }

    public static Test fun2() {
        Test t = new Test();
        return (t);
    }
}

当您查看方法fun1()fun2()的字节码时,它们将如下所示:

public static Test fun1();
  Code:
    0: new           #1                  // class Test
    3: dup
    4: invokespecial #20                 // Method "<init>":()V
    7: areturn

public static Test fun2();
  Code:
    0: new           #1                  // class Test
    3: dup
    4: invokespecial #20                 // Method "<init>":()V
    7: astore_0 // those lines are
    8: aload_0  // unique to fun2()
    9: areturn

执行此代码时,您可能会注意到执行时间越来越快。我认为这是由于JIT编译器。然而,最终,在绩效方面几乎没有差异。

答案 4 :(得分:0)

这两种方法几乎相似。在方法1中,如果在将对象分配给引用变量后立即返回,则将其分配给refence变量没有意义。在这种情况下,方法2应该选择。

Obj temp = new Obj(); //if you are not doing anything with temp but just returning then go with method 2
  return temp;

但是如果你必须改变对象或者做一些操作,那么method1应该是好的,因为你将在'temp'中获得对该对象的引用

Obj temp = new Obj(); //if temp is used before return, then go with method 1
  return temp;

注意:只有对象占用堆上的内存而不是引用变量。

答案 5 :(得分:0)

我和专家讨论过,发现每次创建新对象时,使用以下方法都会在堆栈中创建内存分配。

method1 () {
return new ClassObj();
}
method2 () {
return new ClassObj();
}
method3 () {
return new ClassObj();
}
method4 () {
return new ClassObj();
}
method5 () {
return new ClassObj();
}

并且这个堆栈内存继续分配。如果我们在运行期间多次调用此函数(因为它通常在运行自动脚本中发生)同一个函数一次又一次地调用多次,这个堆栈的累积会继续增加。

所以为了避免这种情况,请使用一些临时对象来捕获方法返回的对象。因此,不是在堆栈中分配内存,而是删除临时对象的先前内存数据并将其替换为新的。

ClassObj temp;
method1 () {
temp = new ClassObj();
return temp;
}
method2 () {
temp = new ClassObj();
return temp;
}
method3 () {
temp = new ClassObj();
return temp;
}
method4 () {
temp = new ClassObj();
return temp;
}
method5 () {
temp = new ClassObj();
return temp;
}