2

我需要在模拟循环中经常调用具有多种方法的类的方法。

其中一些方法需要访问临时对象以在其中存储信息。离开该方法后,不再需要存储的数据。例如:

Class class {      
  method1() {
        ...
        SomeObject temp = new SomeObject();
       ...
  }

  method2() {
        ...
        SomeObject temp = new SomeObject();
        SomeObject temp2 = new SomeObject();
        ...
  }
}

我需要尽可能优化。最昂贵(可移除)的问题是发生了太多的分配。我认为最好不要每次都为这些对象分配所需的空间,所以我想保留它们。

以静态方式存储它们会更有效吗?像:

Class class {
  private (static?) SomeObject temp;
  private (static?) SomeObject temp2;

  methods...
}

还是有更好的方法?感谢您的帮助!

根据答案进行编辑: 实际问题不是内存占用,而是垃圾收集清理混乱。SomeObject 是一个类似 Point2D 的类,没有什么昂贵的内存(在我看来)。我不确定使用(最终是静态的)类级别对象作为占位符还是我不知道的一些更高级的方法是否更好。

4

4 回答 4

3

请记住,tempandtemp2本身不是对象,而是指向类型对象的变量SomeObject。您计划这样做的方式,唯一的区别是实例变量temptemp2不是局部变量。打电话

temp = new SomeObject();

SomeObject仍然会在堆上分配一个新的。

此外,将它们设为静态变量或实例变量而不是本地变量会导致最后分配SomeObject的 s 保持强可访问性(只要您的class实例在实例变量的范围内),防止它们被垃圾收集,直到重新分配变量。

以这种方式优化可能是无效的。目前,一旦temp超出temp2范围,SomeObject它们指向的 s 将有资格进行垃圾收集。

如果您仍然对内存优化感兴趣,您将需要展示它SomeObject是什么,以便获得有关如何缓存它所持有的信息的建议。

于 2011-09-21T20:34:33.147 回答
3

在这个过早优化的例子中,我会保持警惕。通常有缺点,它使代码更复杂(复杂性使错误更有可能),更难阅读,可能引入错误,可能无法提供您期望的加速等。对于一个简单的对象,例如表示 2D 点协调,我不会担心重复使用。如果您使用大量内存,避免冗长的昂贵构造函数,或者将对象构造从频繁执行的紧密循环中拉出,则通常重用会获得最大的好处。

您可以尝试一些不同的策略:

将责任推给调用者一种方法是让调用者传入一个预先初始化的对象,使方法参数成为最终的。但是,这是否可行取决于您需要对对象执行的操作。

指向临时对象的指针作为方法参数另一种方法是让调用者将对象作为参数传递,其目的本质上是指向方法应临时存储的对象的指针。我认为这种技术在 C++ 中更常用,但工作原理类似,尽管有时会出现在图形编程等地方。

对象池重用临时对象的一种常见方法是使用对象池,其中对象是从固定的“可用”对象库中分配的。这有一些开销,但如果对象很大,并且仅在短时间内频繁使用,这样内存碎片可能是一个问题,那么开销可能足够少,值得考虑。

成员变量如果您不关心对该方法的并发调用(或已使用同步来防止这种情况),您可以通过为您的存储创建类的成员变量来模拟“局部静态”变量的 C++ 主义. 它使代码的可读性降低,并且使用变量对代码的其他部分引入意外干扰的空间稍大,但开销低于对象池,并且不需要更改方法签名。如果这样做,您可能还希望transient在变量上使用关键字,以指示该变量不需要序列化。

I would shy away from a static variable for the temporary unless the method is also static, because this may have a memory overhead for the entire time your program runs that is undesirable, and the same downsides as a member variable for this purpose x2 (multiple instances of the same class)

于 2011-09-21T21:58:57.427 回答
1

这些物体有多大。在我看来,您可以拥有类级别的对象(不一定是静态的。我会回到那个)。对于 SomeObject,您可以有一个清除其内容的方法。当您在一个地方完成使用它时,调用该方法以清除其内容。

就静态而言,多个调用者会使用这个类并具有不同的值吗?如果是这样,请不要使用静态。

于 2011-09-21T20:35:12.553 回答
1

首先,你需要确保你真的有这个问题。垃圾收集器的好处是它会自动处理所有临时对象。

无论如何,假设您运行一个单线程应用程序并且您在任何给定时间最多使用 MAX_OBJECTS。一种解决方案可能是这样的:

public class ObjectPool {

    private final int MAX_OBJECTS = 5;
    private final Object [] pool = new Object [MAX_OBJECTS];

    private int position = 0;

    public Object getObject() {

        // advance to the next object
        position = (position + 1) % MAX_OBJECTS;

        // check and create new object if needed
        if(pool[position] == null) {
            pool[position] = new Object();
        }

        // return next object
        return pool[position];
    }

    // make it a singleton
    private ObjectPool() {}
    private static final ObjectPool instance = new ObjectPool();
    public static ObjectPool getInstance() { return instance;}


}

这是使用示例:

public class ObjectPoolTest {

public static void main(String[] args) {
    for(int n = 0; n < 6; n++) {
        Object o = ObjectPool.getInstance().getObject();
        System.out.println(o.hashCode());
    }
}

}

这是输出:

0) 1660364311
1) 1340465859
2) 2106235183
3) 374283533
4) 603737068
5) 1660364311

您会注意到第一个和最后一个数字是相同的 - MAX_OBJECTS + 1 次迭代返回相同的临时对象。

于 2011-09-21T21:04:24.733 回答