I understand that this means I'm using more memory than is available to the JVM, but I'm not sure why or what to do about it.

The purpose of the program is to simulate an item in a store that is being tracked with a bar code id number (or value) for identification purposes. Each item in the store is tracked with both an id value and an inventory amount. The program should take in values from a file, sort them, and print them.

import java.util.*;
import java.io.*;
public class Store {
  Item o;
  ArrayList <Item> myStore = new ArrayList <Item>();
  ArrayList <Item> flipper = new ArrayList <Item>();
	
    public void storeStuff(){
	Scanner in;
	  try{
	     in = new Scanner(new File("/home/chris/Desktop/file50.txt"));
            while(in.hasNext()){
	     o = new Item(in.nextInt(), in.nextInt()); //the item class takes in an Id value and the total inventory for that item
                myStore.add(o);
             }
	  }catch(IOException i){
	    System.out.println("Error: " + i.getMessage());
	  }
		
	}
	
  public void sort(ArrayList <Item> list){
	System.out.println("sorting method accessed");
	int pointer = 0;
	System.out.println(myStore.size() + " myStore");
	System.out.println(flipper.size() + " flipper");
	   for(int i = 0; i < list.size(); i++){
		pointer = 0;
		if(flipper.size() < 1){
                //if a list is empty, simply add an item
		     flipper.add(myStore.get(i));
		}
		else{ 
                //if the item being added to the 2nd arraylist is less than the item currently in that space, insert it, thus pushing back all other values
	           for(int j = 0; j < flipper.size(); j++){
		      if(myStore.get(i).getId() < flipper.get(j).getId()){
			 flipper.add(j, myStore.get(i));
		       }
	           }
			      
		}
	}
    }
    public void run(){
	storeStuff();
	sort(myStore);
        for(int i = 0; i < flipper.size(); i++){
	     System.out.println(flipper.get(i).getId() + "         "  + flipper.get(i).getInv());
	}
   }
}

Recommended Answers

All 10 Replies

What's the size of your data set? Also, there are two types of OutOfMemoryError: out of heap space and out of perma-gen space. What does the error exactly say? Post the exact stacktrace of your application.

Also, there are better ways of sorting a collection containing your custom class. Make your class implement the Comparable interface and define the natural ordering for your class objects. Something like this:

import java.util.*;

public class Item implements Comparable<Item> {
  // TODO: Use getters and setters instead
  public String id;
  public String name;
  
  public Item(String id, String name) {
      this.id = id;
      this.name = name;
  }
  
  @Override
  public int compareTo(Item item) {
    int val = this.id.compareTo(item.id);
    if(val != 0) {
        return val;
    } else {
        return this.name.compareTo(item.name);
    }
  }
  
  @Override
  public String toString() {
      return "[id: " + this.id + ", name: " + this.name + "]";
  }
}

Item item1 = new Item("c", "comb");
Item item2 = new Item("a", "soap");
Item item3 = new Item("b", "shampoo");
List<Item> items = new ArrayList<Item>();
items.add(item1); items.add(item2); items.add(item3);
Collections.sort(items);
System.out.println(items);

Regarding the settings for adjusting memory usage, look into the JVM flags, specifically -Xmx for setting the maximum heap memory and -XX:MaxPermSize . You can then spawn your JVM process using something like:

java -Xmx256M -XX:MaxPermSize=64M your.pkg.YourMainClass

My error is:
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:370)
at Store.sort(Store.java:39) //line that transfers Items
at Store.run(Store.java:52) //line that activates sort method
at Runner.main(Runner.java:6) //class used to test programs, and really has nothing to do with this.

My data set has 50 Items. My Item class is simply

public class Item {
	 private int myId;
	  private int myInv;

	  public Item(int id, int inv){
	    myId = id;
	    myInv = inv;
	  }

	  public int getId(){
		  return myId;
	  }

	  public int getInv(){
		  return myInv;
	  }
	  
}

The lesson actually showed something similar to what you posted, but I don't understand what the compareTo and toString classes are supposed to do. I'm taking in integers, why should I treat them as strings? If you could give me a brief explanation I'd appreciate it. As for my code, eclipse should allow up to 512mb of RAM usage. I really doubt I'm using all that by copying 50 data pairs in a list, and transferring them to a second list.

You can read more about compareTo here and about the toString method here; ask again if you have any *specific* questions.

Regarding ID's, it's generally a good idea to represent ID's as string since it doesn't restrict the usage of other non-numeric characters when you actually need them. Anyways, if you still plan on using numbers, you can replace to string `id` variable in my post with your integer variable and there shouldn't be any problems as such.

Regarding eclipse; your code which you execute runs/executes in a separate JVM process which is different from the JVM process which runs eclipse. If you are using Eclipse, you need to alter the run configuration of your main class to modify the heap settings for that particular java program execution. Though I think that the problem really isn't the lack of heap memory but a sort implementation gone wrong; more specifically the part where you modify the collection as well as keep looping over it. Try using the standard sort implementation and the problem should most probably go away.

Thank you for your help. I read your links and code, and changed my Item class to

public class Item{
  private Integer id;
  private Integer inv;

  public Item(int id, int inv){
    this.id = id;
    this.inv = inv;
  }

  public int getId(){
	  return id;
  }

  public int getInv(){
	  return inv;
  }

  public int compareTo(Item other){
	  return this.id.compareTo(other.id);
  }

  public boolean equals(Item other){ 
  	if(this.id.compareTo(other.id) == 0){
  		return true;
  	}
  	else{
  		return false;
  	}
  }
  public String toString(){
	  String a = "Id: " + this.id + "    " + "Inv: " + this.inv;
	  return a;
  }
}

Regarding the store class; I don't think I can use Collections.sort() because I don't have a "standard" list of integers or string, but integer pairs. I guess I don't understand how to implement a sorting algorithm other than the one I tried above to sort Items based on their Id.

I tried to use

public void sort(ArrayList <Item> list){
     for (int outer = 0; outer < list.size() - 1; outer++){
         for (int inner = 0; inner < list.size()-outer-1; inner++){
	     if (list.get(inner).getId()>(list.get(inner + 1).getId())){
		Item temp = list.get(inner);
		list.set(inner,list.get(inner + 1));
		list.set(inner + 1,temp);
		}
	}
     }
}

Yeah, I know, bubble sort sucks, but it's easy to write. Anyway, the above method just jumbled my list even more.

Collections.sort() automatically takes cares of all the details as long as all the objects present in the collection (in your case a list) implement the Comparable interface (which you already have). Try passing your list to the Collections.sort() method and it *should* work out to be fine. If it doesn't, give specific details as to what output you got and what you were expecting.

see below

Collections.sort() automatically takes cares of all the details as long as all the objects present in the collection (in your case a list) implement the Comparable interface (which you already have). Try passing your list to the Collections.sort() method and it *should* work out to be fine. If it doesn't, give specific details as to what output you got and what you were expecting.

Okay, I'll try to do this the proper way, using Collections.

public void sort(ArrayList <Item> list){
  Collections.sort(list);
}

returns the error:
Bound mismatch: The generic method sort(List<T>) of type Collections is not applicable for the arguments (ArrayList<Item>). The inferred type Item is not a valid substitute for the bounded parameter <T extends Comparable<? super T>>

I want to take
[Id: 3679 Inv: 87
, Id: 196 Inv: 60
, Id: 17914 Inv: 12
, Id: 18618 Inv: 64 etc.

and instead print out
, Id: 206 Inv: 31
, Id: 13066 Inv: 8
, Id: 19623 Inv: 88 etc.

Thank you for your continued help.

The error says that your Item class doesn't implement the Comparable<Item> interface; see my first post for the same.

The error says that your Item class doesn't implement the Comparable<Item> interface; see my first post for the same.

This seems to be working. If you don't mind answering one last thing, how can I setup toString to add a blank line every ten Item?

In any case, thanks a lot.

That isn't the responsibility of the toString() method of the Item class. If you need something like this, there are a couple of approaches you can adopt:
- Create a static utility method in a helper class which does the same (i.e. blank line after 10 items)
- Create a new abstraction; Store class which acts as a thin wrapper around the ArrayList and override its toString() method to do the same. The store arraylist in your main class will now be replaced by a variable of the Store class. Something like:

class Store {
  public List<Item> items = new ArrayList<Item>();

  public void addItem(Item item) {}

  public void removeItem(Item item) {}

  public String toString() {
    // loop over the items in the store/cart and add a blank
    // line every ten items
  }
}

I would personally prefer the second approach since it's much cleaner.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.