Java中超大ArrayList的解决方法,求指导 arraylistjava 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 arraylist好像增删比较慢linkedlist比较适合频繁增删的 数据量巨大,是不是可以考虑异步读写?边读边写,一个共享的buffer 感谢回复,我这里好像没有频繁增删,主要是添加元素数量比较大。我研究下linkedlist试一下。 问题:1、大文件一次性读入会占用很多的内存,轻则拖慢应用,重则系统崩溃。2、读入内存,一次性保存在一个ArrayList中会进一步增加内存空间消耗。解决方法: 大文件不要一次性读入内存,逐行处理,取一行处理一行。这样后面用到的ArrayList需要存储的值也自然少了。 为了加快处理速度,可以使用多线程等方式并发处理,对刚接触Java的人来讲还略早。 感谢回复,我这里好像没有频繁增删,主要是添加元素数量比较大。我研究下linkedlist试一下。好像有个因素默认0.75,list生成时候有个默认大小,然后里面存到0.75比例就要扩容,不停存要不听扩,扩的过程会比linkedlist慢然后要边读边处理好像可以用ArrayBlockingQueue之类的,线程安全方便多线程 啊记错了...那个0.75是HashMap的...后面那部分扩容是对的应该,两种list实现的方法不一样 while (scanner.hasNext()){ double orix,oriy,dirx,diry; int hitcount,raynum; if (scanner.hasNextDouble()){ orix=scanner.nextDouble();oriy=scanner.nextDouble(); dirx=scanner.nextDouble();diry=scanner.nextDouble(); hitcount=(int)scanner.nextDouble(); raynum=(int)scanner.nextDouble(); ray newRay=new ray(orix,oriy,dirx,diry,hitcount); newRay.setNo(raynum); InputRays.add(newRay); } else { String temp=scanner.next(); } }这样写有问题,因为你将创建的对象放入list中,垃圾回收机制是不能回收被list持有的对象,如果对象太多就会内存溢出。你可以一次创建5000个对象,将这些对象存入文件或者数据库中。这样就不会内存溢出了。 感谢回复。我爬网学习下你说的这个方法。随便写了个。没做测试,不确定有没有错。反正大致就是这么个思路用到了多线程、锁、匿名类、区块等等。本来还想用lambda表达式的,但是怕楼主jdk版本不够高……Ray[] buffer = new Ray[100];{ for (int i=0;i<100;i++) { buffer[i] = new Ray(); }}int readPointer = 0;int processPointer = 0;int size = 0;boolean eof = false;public void readRays(final String f) { new Thread() { public void run() { Scanner scanner = new Scanner(new FileInputStream(f))); while (scanner.hasNext()){ synchronized(buffer) { if (size == 100) { buffer.wait(); } else { ray[readPointer].orix = scanner.nextDouble(); ray[readPointer].oriy = scanner.nextDouble(); ray[readPointer].dirx = scanner.nextDouble(); ray[readPointer].diry = scanner.nextDouble(); ray[readPointer].hitcount = (int)scanner.nextDouble(); ray[readPointer].raynum = (int)scanner.nextDouble(); size++; readPointer = readPointer == 99 ? 0 : readPointer + 1; if (size == 1) { buffer.notifyAll(); } } } } eof = true; } }.start();}public void processRays() { new Thread() { public void run() { while (!eof){ synchronized(buffer) { if (size == 0) { buffer.wait(); } else { processRay(ray[processPointer]); size--; processPointer = processPointer == 99 ? 0 : processPointer + 1; if (size == 99) { buffer.notifyAll(); } } } } } }.start();} 等等……稍微想了下,感觉楼上的方法是错误的。直接锁整个buffer导致两个线程无法同时进行,效率反而比单线程更低。应该用 synchronized( buffer [pointer] ) (行级锁) 嗯,hashmap是为了防止hash碰撞,所以要留一部分空间。arraylist满了才扩容但是扩容主要影响的应该是cpu和内存读写速度,而不是内存容量。扩容后原本的数组会被垃圾回收的 不建议楼主一次性全部读取, 搜下java大型文件读取,有很多资料的 你的想法是对的。ArrayList本身底层的实现就决定了你处理的对象越多就会越慢,因为底层是固定长度的数组,你不停的加数据就涉及到数据扩容,扩容就涉及内存的拷贝,所以你看到的现象就是你的对象越多,扩容的速度就会越慢,最后就把你内存吃光。正确的处理思路就是适当的批量,比如你在ArrayList里一次性只装10000个,处理完了再装10000个 感谢回复。大文件的确应该边读边处理边释放资源,类似流式那样。多线程并发处理是高端了点,容我学习研究一番。收获关键词多线程并发处理,感谢。爬网查了下。arraylist扩容的确要慢点,我试试改成别的看看效率。感谢提供关键词ArrayBlockingQueue,我研究一下看看。感谢回复。这些对象后面还要用到,如果存到文件或者数据库,后面用的时候还是要加载到内存的吧。还是说也是边读边处理这样?或者你的意思是这样读取,垃圾回收机制就可以工作了?还请指导。非常感谢,还有例程,免了我爬网找例程之苦。多线程、匿名类、锁、区块我还没接触到,先学习研究一下。感谢提供关键词及例程。感谢回复。的确不能一次读取,后面我又试了一个GB级别的文件,直接内存不够了。感谢回复。批量处理看上去挺不错,可能没有边读边处理和多线程并发处理优雅高效,但对我这样技术小白应该是容易上手的,可以先从这里研究看看。 ArrayList底层是用数组来实现的,你不断往里加内容,导致数组不断变长。一开始数据量小数组拷贝还好,到后来数组变大,拷贝当然耗时解决方法就是一开始创建ArrayList时给足够的初始长度,这样后面就不用每次改变数组长度了List list = new ArrayList(100000) 希望能帮到你 不知道如何让打开的文件采用unicode的编码方式编码,求解答 数据库查询问题,乱码的奇怪现象 web应用程序客户端离线判断功能 在线程中使用链表,效率变的非常慢,苦恼中 请问JPopupMenu如何改变外观? 谁整理过位操作吗~-~, 哪位高人知道在java中如何判断一个文件是以gbk方式存储的还是unicode方式存储的? 请问时间的输入 请高手帮忙: 静态变量向前引用问题 java poi 导出excel不能超过65536行 Apache lucene RangeQuery jar包
linkedlist比较适合频繁增删的
1、大文件一次性读入会占用很多的内存,轻则拖慢应用,重则系统崩溃。
2、读入内存,一次性保存在一个ArrayList中会进一步增加内存空间消耗。解决方法:
大文件不要一次性读入内存,逐行处理,取一行处理一行。这样后面用到的ArrayList需要存储的值也自然少了。
为了加快处理速度,可以使用多线程等方式并发处理,对刚接触Java的人来讲还略早。
然后要边读边处理好像可以用ArrayBlockingQueue之类的,线程安全方便多线程
两种list实现的方法不一样
double orix,oriy,dirx,diry;
int hitcount,raynum;
if (scanner.hasNextDouble()){
orix=scanner.nextDouble();oriy=scanner.nextDouble();
dirx=scanner.nextDouble();diry=scanner.nextDouble();
hitcount=(int)scanner.nextDouble();
raynum=(int)scanner.nextDouble();
ray newRay=new ray(orix,oriy,dirx,diry,hitcount);
newRay.setNo(raynum);
InputRays.add(newRay);
}
else {
String temp=scanner.next();
}
}
这样写有问题,因为你将创建的对象放入list中,垃圾回收机制是不能回收被list持有的对象,如果对象太多就会内存溢出。你可以一次创建5000个对象,将这些对象存入文件或者数据库中。这样就不会内存溢出了。
用到了多线程、锁、匿名类、区块等等。本来还想用lambda表达式的,但是怕楼主jdk版本不够高……
Ray[] buffer = new Ray[100];
{
for (int i=0;i<100;i++) {
buffer[i] = new Ray();
}
}
int readPointer = 0;
int processPointer = 0;
int size = 0;
boolean eof = false;public void readRays(final String f) {
new Thread() {
public void run() {
Scanner scanner = new Scanner(new FileInputStream(f)));
while (scanner.hasNext()){
synchronized(buffer) {
if (size == 100) {
buffer.wait();
} else {
ray[readPointer].orix = scanner.nextDouble();
ray[readPointer].oriy = scanner.nextDouble();
ray[readPointer].dirx = scanner.nextDouble();
ray[readPointer].diry = scanner.nextDouble();
ray[readPointer].hitcount = (int)scanner.nextDouble();
ray[readPointer].raynum = (int)scanner.nextDouble();
size++;
readPointer = readPointer == 99 ? 0 : readPointer + 1;
if (size == 1) {
buffer.notifyAll();
}
}
}
}
eof = true;
}
}.start();
}public void processRays() {
new Thread() {
public void run() {
while (!eof){
synchronized(buffer) {
if (size == 0) {
buffer.wait();
} else {
processRay(ray[processPointer]);
size--;
processPointer = processPointer == 99 ? 0 : processPointer + 1;
if (size == 99) {
buffer.notifyAll();
}
}
}
}
}
}.start();
}
但是扩容主要影响的应该是cpu和内存读写速度,而不是内存容量。扩容后原本的数组会被垃圾回收的
爬网查了下。arraylist扩容的确要慢点,我试试改成别的看看效率。感谢提供关键词ArrayBlockingQueue,我研究一下看看。
感谢回复。这些对象后面还要用到,如果存到文件或者数据库,后面用的时候还是要加载到内存的吧。还是说也是边读边处理这样?或者你的意思是这样读取,垃圾回收机制就可以工作了?还请指导。
非常感谢,还有例程,免了我爬网找例程之苦。多线程、匿名类、锁、区块我还没接触到,先学习研究一下。感谢提供关键词及例程。
感谢回复。的确不能一次读取,后面我又试了一个GB级别的文件,直接内存不够了。
感谢回复。批量处理看上去挺不错,可能没有边读边处理和多线程并发处理优雅高效,但对我这样技术小白应该是容易上手的,可以先从这里研究看看。
解决方法就是一开始创建ArrayList时给足够的初始长度,这样后面就不用每次改变数组长度了
List list = new ArrayList(100000)
希望能帮到你