我有一个方法,每5秒迭代一个大型数组。在每个循环中,我向ArrayList
添加内容。
我听说使用new
会占用更多内存。
我需要知道上面ArrayList
清空/清除的最佳方法是什么。
private ArrayList<MyMarker> myArray;
public void callEveryFiveSeconds(){
myArray = new ArrayList<MyMarker>(); //clears previous array data
//grab array data from server
for (int i = 0; i < 200; i++) {
myArray.add(someData);
}
}
或
private ArrayList<MyMarker> myArray = new ArrayList<MyMarker>();
public void callEveryFiveSeconds(){
myArray = null; //clears previous array data
//grab array data from server
for (int i = 0; i < 200; i++) {
myArray.add(someData);
}
}
答案 0 :(得分:10)
第二个代码错误,将抛出NullPointerException。
如果要清除列表:
public void callEveryFiveSeconds(){
myArray.clear();
//grab array data from server
for (int i = 0; i < 200; i++) {
myArray.add(someData);
}
}
关于哪个选项更好 - 创建新的ArrayList
实例或清除现有实例 - 后者应该占用更少的内存,因为它不必为新的{{1}分配新数组}。前者将使用新数组分配新的ArrayList
,旧的ArrayList
将有资格进行垃圾回收。这意味着第二个选项(清除列表)将节省垃圾收集器的工作,这在性能方面也是一件好事。
如果在ArrayList
的每次调用中添加到列表中的元素数量保持相似,则每次清除现有列表而不是创建新列表会有另一个好处。这样做的原因是创建新的callEveryFiveSeconds
而不指定初始容量会创建一个初始容量较小的列表,如果向新列表中添加许多元素,则必须多次调整大小,这也是花费时间。
答案 1 :(得分:2)
您正在做的事情称为过早优化。如果您每5秒钟只调用一次方法,那么您应该正常编写代码,而不考虑微优化。如果您的程序在现代处理器上运行,那么它将能够在每个方法调用之间执行数百亿条指令。优化这一方法不会对程序的性能产生任何影响。记住,你的数组列表似乎只有200个项目。在64位操作系统上,阵列列表需要不到2kB才能保存所有必需的内存资源。当现代计算机拥有数十亿字节的内存时,在宏观计划中也没有多少。
实际上,您可以使用ArrayList.clear
为您的计划创作更多作品,而不是创建新的ArrayList
。这是因为通过清除ArrayList
程序必须将后备阵列中的每个项目设置为null
。但是,Java的垃圾收集器非常有效,当它处理一个未使用的ArrayList
时,它能够在不先清除它的情况下处理后备阵列。
鉴于我的计算机上有以下微基准测试,每个基准测试运行一千万次:
public static final Object OBJ = new Object();
public static final int LENGTH = 200;
public static ArrayList<Object> clearArrayList(ArrayList<Object> objects) {
objects.clear();
for (int i = 0; i < LENGTH; i++) {
objects.add(OBJ);
}
return objects;
}
public static ArrayList<Object> newArrayList() {
ArrayList<Object> objects = new ArrayList<Object>(LENGTH);
for (int i = 0; i < LENGTH; i++) {
objects.add(OBJ);
}
return objects;
}
每次调用newArrayList
的结果为870纳秒,每次调用clearArrayList
的结果为970纳秒。因此,您可以看到使用新ArrayList
的速度略快,但不足以关注。特别是当你谈论每5秒100 ns的差异时。您会注意到我为新运行预先调整了ArrayList
的大小。当ArrayList没有预先调整大小时,平均调用时间为1690ns。虽然这个时间延长了50%,但仍然不足以关心,因为你没有足够的称呼这种方法。
那为什么要用这两种方式?使用新的ArrayList
有一个好处,这就是它可以更好地与线程同步。如果您反复使用相同的ArrayList,则必须阻止其他线程在您进行变异时访问ArrayList。如果您使用新的ArrayList
,则可以在将其用于其他线程访问之前,私下创建新的ArrayList
。
例如
private ArrayList<Object> objects = new ArrayList<Object>();
private final Object lock = new Object();
public ArrayList<Object> getObjects() {
synchronized(lock) {
return objects;
}
}
public void setObjects(ArrayList<Object> newObjects) {
synchronized(lock) {
objects = newObjects;
}
}
public void callEveryFiveSeconds() {
// note that this method does not explicitly use synchronisation.
// Synchronisation is only used when setting objects.
ArrayList<Object> newObjects = new ArrayList<Object>();
for (int i = 0; i < 200; i++) {
newObjects.add(new Object());
}
setObjects(newObjects);
}
答案 2 :(得分:1)
有一个名为clear()的方法清空了一个arraylist:
public void callEveryFiveSeconds(){
myArray.clear();
//grab array data from server
for (int i = 0; i < 200; i++) {
myArray.add(someData);
}
}