我必须在内存中保留数千个字符串,以便在Java中串行访问。我应该把它们存储在数组中还是应该使用某种列表?
由于数组将所有数据保存在一个连续的内存块中(与list不同),使用数组存储数千个字符串会导致问题吗?
我必须在内存中保留数千个字符串,以便在Java中串行访问。我应该把它们存储在数组中还是应该使用某种列表?
由于数组将所有数据保存在一个连续的内存块中(与list不同),使用数组存储数千个字符串会导致问题吗?
当前回答
您应该更喜欢泛型类型而不是数组。正如其他人所提到的,数组是不灵活的,不具有泛型类型的表达能力。(它们确实支持运行时类型检查,但这与泛型类型混在一起很糟糕。)
但是,与往常一样,在优化时,你应该始终遵循以下步骤:
Don't optimize until you have a nice, clean, and working version of your code. Changing to generic types could very well be motivated at this step already. When you have a version that is nice and clean, decide if it is fast enough. If it isn't fast enough, measure its performance. This step is important for two reasons. If you don't measure you won't (1) know the impact of any optimizations you make and (2) know where to optimize. Optimize the hottest part of your code. Measure again. This is just as important as measuring before. If the optimization didn't improve things, revert it. Remember, the code without the optimization was clean, nice, and working.
其他回答
更新:
正如Mark所指出的那样,在JVM预热之后(几次测试通过)没有明显的差异。检查与重新创建的数组,甚至新传递开始的新行矩阵。有很大的可能性,这表明简单数组的索引访问不用于有利于集合。
前1-2次简单数组还是快2-3倍。
原来的帖子:
对这个主题来说,太多的词太简单了。毫无疑问,数组比任何类容器都快几倍。我在这个问题上为我的性能关键部分寻找替代方案。下面是我为检查实际情况而构建的原型代码:
import java.util.List;
import java.util.Arrays;
public class IterationTest {
private static final long MAX_ITERATIONS = 1000000000;
public static void main(String [] args) {
Integer [] array = {1, 5, 3, 5};
List<Integer> list = Arrays.asList(array);
long start = System.currentTimeMillis();
int test_sum = 0;
for (int i = 0; i < MAX_ITERATIONS; ++i) {
// for (int e : array) {
for (int e : list) {
test_sum += e;
}
}
long stop = System.currentTimeMillis();
long ms = (stop - start);
System.out.println("Time: " + ms);
}
}
这就是答案:
基于数组(第16行是活动的):
Time: 7064
根据列表(第17行是活动的):
Time: 20950
还有关于“更快”的评论吗?这是可以理解的。问题是什么时候大约3倍的速度比List的灵活性更好。但这是另一个问题。 顺便说一下,我也根据手工构造的数组列表检查了这个。几乎是一样的结果。
数组更快-所有内存都是预先分配的。
A List更灵活....所以List比array更好
我不认为这对Strings有什么影响。字符串数组中连续的是对字符串的引用,字符串本身存储在内存中的随机位置。
数组与列表的区别在于基本类型,而不是对象。如果您预先知道元素的数量,并且不需要灵活性,那么由数百万个整数或双精度数组成的数组将比列表在内存和速度上更有效,因为它们确实是连续存储的,并且可以立即访问。这就是为什么Java仍然使用字符数组表示字符串,使用整数数组表示图像数据,等等。
这里给出的许多微基准测试发现,像array/ArrayList读取这样的事情需要几纳秒。如果所有内容都在L1缓存中,这是非常合理的。
更高级别的缓存或主存访问的数量级可能是10nS-100nS,而L1缓存的数量级更接近1nS。访问ArrayList有一个额外的内存间接,在实际的应用程序中,你可以几乎从不或每次都支付这个代价,这取决于你的代码在访问之间所做的事情。当然,如果你有很多小的数组列表,这可能会增加你的内存使用,使你更有可能缓存丢失。
原来的海报似乎只使用一个,在短时间内访问了很多内容,所以应该没有太大的困难。但是对于其他人来说可能有所不同,在解释微基准测试时应该注意。
Java Strings, however, are appallingly wasteful, especially if you store lots of small ones (just look at them with a memory analyzer, it seems to be > 60 bytes for a string of a few characters). An array of strings has an indirection to the String object, and another from the String object to a char[] which contains the string itself. If anything's going to blow your L1 cache it's this, combined with thousands or tens of thousands of Strings. So, if you're serious - really serious - about scraping out as much performance as possible then you could look at doing it differently. You could, say, hold two arrays, a char[] with all the strings in it, one after another, and an int[] with offsets to the starts. This will be a PITA to do anything with, and you almost certainly don't need it. And if you do, you've chosen the wrong language.