Fala pessoal, preciso pegar alguns atributos de uma classe e agrupá-los em uma arraylist, no início foi fácil, agora me compliquei!
O compilador está acusando que minha ArrayList (CountryList) está vazia dentro da função countryCounter, nas linhas onde o código “for (int i = 0; i <= CountryList.size(); i++) {” aparece, ele acusa de estar dando erro ou no comando size() (diz que está em 0) e se eu inicio com algum objeto, o erro “java.lang.OutOfMemoryError: Java heap space” aparece.
O que pode ser?
Eis o código:
[code]public class Main {
//Matriz com 3 colunas para armazenar as informações necessárias (Nome, ID, Country Name)
static ArrayList<Notice> NewsList = new ArrayList<Notice>();
static ArrayList<Country> CountryList = new ArrayList<Country>();
public static void main(String[] args) throws JDOMException, IOException {
for (int i = 0; i < files.length; i++) {
//aqui o código foi omitido, basicamente eu pego strings de vários arquivos textos e mando para o countryCounter.
countryCounter(countryName);
}
for (int i = 0; i < CountryList.size(); i++) {
System.out.println(CountryList.get(i).getName());
System.out.println(CountryList.get(i).getFrequency());
}
}
public static void countryCounter(String countryName) {
if (CountryList.isEmpty()) {
Country country = new Country();
country.setFrequency(1);
country.setName(countryName);
CountryList.add(country);
} else {
for (int i = 0; i <= CountryList.size(); i++) {
if (CountryList.get(i).equals(countryName)) {
CountryList.get(i).incrementFrequency();
} else {
Country country = new Country();
country.setFrequency(1);
country.setName(countryName);
CountryList.add(country);
}
}
}
}
em uma rápida olhada, vi que você colocou “for (int i = 0; i <= CountryList.size(); i++) {”, quando o correto seria “for (int i = 0; i < CountryList.size(); i++) {”, já que o java começa a contar os elementos em 0, se o tamanho dele é 0, você roda esse código pelo menos uma vez. (mas só vi isso na sua definição do problema, não no código)
Outra coisa, se você for carregar um arquivo grande na memória, vai dar java heap space mesmo, qual o tamanho do arquivo que você quer carregar?
[quote=evefuji]em uma rápida olhada, vi que você colocou “for (int i = 0; i <= CountryList.size(); i++) {”, quando o correto seria “for (int i = 0; i < CountryList.size(); i++) {”, já que o java começa a contar os elementos em 0, se o tamanho dele é 0, você roda esse código pelo menos uma vez. (mas só vi isso na sua definição do problema, não no código)
Outra coisa, se você for carregar um arquivo grande na memória, vai dar java heap space mesmo, qual o tamanho do arquivo que você quer carregar? [/quote]
É uma lista de arquivos XML, to trabalhando com 100, mas precisarei trabalhar com N.
Tudo da 344kb.
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2760)
at java.util.Arrays.copyOf(Arrays.java:2734)
at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
at java.util.ArrayList.add(ArrayList.java:351)
at cpdfinal.Main.countryCounter(Main.java:81)
at cpdfinal.Main.main(Main.java:50)
Java Result: 1
Bom, você pode adicionar o parâmetro -Xmx512m (para permitir que ele use até 512MB de heap), para solucionar esse problema, mas, não é o mais indicado (ainda mais porque vai trabalhar com N registros).
O mais indicado é que você não tenha que carregar todos na memória. Tente não ler tudo de uma vez, e liberar posições do ArrayList sempre que possível.
Talvez você explicando melhor o que quer fazer (para que vai usar essa arraylist), possamos te ajudar melhor.
Uma sugestão (caso seja muito complexo o seu problema), é você criar duas trheads, em uma delas você lê o XML, e em outra você faz o processamento com os dados do XML (por exemplo, um objeto HashTable compartilhado entre as duas threads) de forma que você leia e execute o processamento necessário, e já dê um “remove()” nesse elemento.
Outra sugestão seria carregar eles num banco de dados.
[quote=evefuji]Bom, você pode adicionar o parâmetro -Xmx512m (para permitir que ele use até 512MB de heap), para solucionar esse problema, mas, não é o mais indicado (ainda mais porque vai trabalhar com N registros).
O mais indicado é que você não tenha que carregar todos na memória. Tente não ler tudo de uma vez, e liberar posições do ArrayList sempre que possível.
Talvez você explicando melhor o que quer fazer (para que vai usar essa arraylist), possamos te ajudar melhor.
Uma sugestão (caso seja muito complexo o seu problema), é você criar duas trheads, em uma delas você lê o XML, e em outra você faz o processamento com os dados do XML (por exemplo, um objeto HashTable compartilhado entre as duas threads) de forma que você leia e execute o processamento necessário, e já dê um “remove()” nesse elemento.
Outra sugestão seria carregar eles num banco de dados.[/quote]
Opa, muito obrigado pela ajuda.
O problema é o seguinte, preciso ler arquivos .xml de uma pasta, processá-los de alguma forma (estou armazenando a tag root de todos em uma ArrayList), depois preciso pegar uma tag país desse xml e agrupar, fazer um ranking de frequência, quais países foram mencionados nos arquivos .xml e quantas vezes.
De qualquer forma, o sistema tranca só quando insiro milhares de XML, não precisa ser tanto, o erro está na recursão dessa função. Ele fica em loop já que eu insiro um item na minha Array e depois eu meço o tamanho dela, assim quando o array aumenta de tamanho, o laço também aumenta :S
public static void countryCounter(String countryName) {
if (CountryList.isEmpty()) {
Country country = new Country();
country.setFrequency(1);
country.setName(countryName);
CountryList.add(country);
} else {
for (int i = 0; i < CountryList.size(); i++) {
if (CountryList.get(i).equals(countryName)) {
CountryList.get(i).incrementFrequency();
} else {
Country country = new Country();
country.setFrequency(1);
country.setName(countryName);
System.out.println(CountryList.size());
CountryList.add(country);
}
}
}
}
se puder trabalhar com isso numa base de dados é bem melhor, pois quando a base de dados não consegue carregar todos os dados na memória, eles usam spool para isso.
Sem falar que é muito otimizado, para não perder desempenho. Mas, se é só fazer a contagem (se o processamento não for muito grande), você pode guardar somente os países no arraylist, e quantas vezes ele aparece. Seria bem mais rápido e não consumiria tanta memória.
[quote=evefuji]se puder trabalhar com isso numa base de dados é bem melhor, pois quando a base de dados não consegue carregar todos os dados na memória, eles usam spool para isso.
Sem falar que é muito otimizado, para não perder desempenho. Mas, se é só fazer a contagem (se o processamento não for muito grande), você pode guardar somente os países no arraylist, e quantas vezes ele aparece. Seria bem mais rápido e não consumiria tanta memória.
[/quote]
O sistema deveria ser simples :S não deveria precisar usar uma base de dados.
Se não der certo vou seguir o seu conselho e usar uma arraylist mais simplificada mesmo.
Mas ainda acho que o problema deve ser mais tosco do que parece…
Porque diabos o tamanho da lista de países aumenta dessa forma?
public static void countryCounter(String countryName) {
if (CountryList.isEmpty()) {
Country country = new Country();
country.setFrequency(1);
country.setName(countryName);
CountryList.add(country);
} else {
int countryListSize = CountryList.size();
System.out.println(countryListSize);
for (int i = 0; i < countryListSize; i++) {
if (CountryList.get(i).getName().equalsIgnoreCase(countryName)) {
CountryList.get(i).incrementFrequency();
} else {
Country country = new Country();
country.setFrequency(1);
country.setName(countryName);
CountryList.add(country);
}
}
}
}
1
2
3
4
7
10
20
40
73
106
212
351
490
629
768
1536
2304
4608
9216
18432
36864
73728
147456
294912
589824
884736
1179648
2285568
4571136
9142272
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2760)
at java.util.Arrays.copyOf(Arrays.java:2734)
at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
at java.util.ArrayList.add(ArrayList.java:351)
at cpdfinal.Main.countryCounter(Main.java:88)
at cpdfinal.Main.main(Main.java:55)
Java Result: 1
for (int i = 0; i < countryListSize; i++) {
if (CountryList.get(i).getName().equalsIgnoreCase(countryName)) {
CountryList.get(i).incrementFrequency();
} else {
Country country = new Country();
country.setFrequency(1);
country.setName(countryName);
CountryList.add(country);
}
} Para cada país que você verifica e não é o mesmo país que você está comparando, você adiciona ele (trocentas vezes)
Por exemplo, se você tem a seguinte lista:
[]Brasil
[]Paraguai
[*]Espanha
E você vai comparar um novo Paraguai, quando você compara com Brasil, você insere um Paraguai, quando compara com paraguai você incrementa, e quando você compara com Espanha, insere outro Paraguai. Entendeu?
Tenho uma sugestão (para questão de desempenho, não para corrigir sua lógica), use um HashSet, implemente o método equals e use o método contains (das Collections, ou seja, o ArrayList também tem), para verificar se um elemento existe ou não.
Repare que para pesquisar você vai precisar de um iterator.
Ou ainda, se você quiser ser mais prático (e consumir mais memória e menos processamento), você pode usar um HashMap.
Edit: enquanto eu digitava isso vc achou o problema, rsrsrs