Link to home
Start Free TrialLog in
Avatar of jjackson2004
jjackson2004Flag for United States of America

asked on

java program getting out of memory error

It is getting an out of memory error.  Feel it is something with the borrowed ArrayQueue class at the end of the code.  No matter what I try, can't get around the damn error message.  I get the feeling that I am getting rightward creep in the array.  Should there be a shift in the array somewhere?

please help!!!!  I am at a deadline.


import java.util.Scanner;

public class bank {

 //  initalize global variables
 static ArrayQueue waitingCustomers= null;
 static ArrayQueue finishedCustomers=null;
 static Customer tellerWindow[] = new Customer[6];
 static Teller tellerArray[]= new Teller[6];
 static int tstTotCusts = 0;
 static int tstTotServed = 0;
 static int tstCustomersInQueue= 0;
 static int tstCustomersinFinishedQueue=0;
 static long nextCustomerTime;
 static Customer newCustomer = null;
 static Customer finishedCustomer = null;
 static Customer waitCustomer = null;
 static Teller Teller1 = null;
 static Teller Teller2 = null;
 static Teller Teller3 = null;
 static Teller Teller4 = null;
 static Teller Teller5 = null;
 static long startTime = 0;
static boolean waitCustQueueEmpty = false;
static boolean finiCustQueueEmpty = true;

 public static void main(String[] args) {

//    String inAnsYN = "N";  // Declare & initialize a String to hold input.
    Scanner inAns = new Scanner(System.in); // Decl. & init. a Scanner.

    while (true){

    boolean loopEnd = false;
    workLoop();
    endPrintout();
    while (!loopEnd){
    System.out.println("Do you want to run the program again? (Y/N) ");
    char cInAns=inAns.next().charAt(0);

    if (cInAns=='Y' || cInAns=='y') loopEnd=true;
    else if (cInAns=='N' || cInAns=='n') return;
    }
    }
  }
// ============================================================================
  private static void workLoop(){
    initVars();
    boolean firstTime=true;
    int custLoopCT = 0;

     //  go ahead and set loop start time
    startTime =  System.currentTimeMillis();
    //  go ahead and populate queue with 5 customers per jbhola
    waitingCustomers = new ArrayQueue();
    finishedCustomers = new ArrayQueue();
    for (int i = 0; i < 5; i++) createCust();

    nextCustomerTime=startTime+getRandomNum(2,6)*100;
    //  go ahead and assign first teller randonmly per jbhola
    assignTeller(getRandomNum(2,5));
   long tstTime = System.currentTimeMillis();

    // =========>  MAIN LOOP  <========
    while (System.currentTimeMillis() < startTime+12000){
//      long loopBeginTime= System.currentTimeMillis();
      bankLoop();
  tstTime = System.currentTimeMillis();

    }

     long endTime =  System.currentTimeMillis();

  }
// ===========================================================================
  private static void bankLoop(){
    long loopStartTime=System.currentTimeMillis();
    if (loopStartTime>nextCustomerTime){
        createCust();
    }
    // teller loop
    for (int j = 1;j<6;j++){
      if (tellerArray[j].available || tellerWindow[j].empty){
          assignTeller(j);
      }
      else  if (tellerWindow[j].endTime < loopStartTime){
          clearTeller(j);
      }
    }
     
  }
 
// ===========================================================================
  private static void createCust(){
    Customer outCust = new Customer(getRandomNum(2,5));

    outCust.intervalTime=getRandomNum(2,5)*1000;
    //  push onto newCustomerQueue
    try {
        waitingCustomers.enqueue(outCust);
        tstCustomersInQueue++;
    } catch (NullPointerException e){
        System.out.println("Error adding to queue");
    } catch (OutOfMemoryError e){
        System.out.println("Out of memory enqueuing customer");
    }
  }
// ===========================================================================
  private static Customer getNextCust(){
    Customer outCust = waitingCustomers.dequeue();
    if  (waitCustQueueEmpty) {;
         outCust = new Customer();
         return outCust;
        }
    nextCustomerTime=startTime+getRandomNum(2,6)*100;
    tstCustomersInQueue--;
    return outCust;
  }
  // ===========================================================================
  private static void initVars(){

 waitingCustomers= null;
 finishedCustomers=null;
 tstTotCusts = 0;
 tstTotServed = 0;
 tstCustomersInQueue= 0;
 tstCustomersinFinishedQueue=0;
nextCustomerTime=0;
newCustomer = null;
 finishedCustomer = null;
waitCustomer = null;
initTellers();
 startTime = 0;  }
  // ===========================================================================
  private static void initTellers(){
for (int t = 0;t<6;t++){
    tellerWindow[t]= new Customer();
    tellerArray[t]=new Teller();
}
  }
// ==========================================================================
  private static void assignTeller(int tellerNum){
     // need way to tell if customer already in teller array cell
     tellerWindow[tellerNum]=getNextCust();
  /// need some check  to make sure there was a customer in queue
     tellerWindow[tellerNum].setTeller(tellerNum);
     // setting start time also sets endtime
     tellerWindow[tellerNum].setStartTime(System.currentTimeMillis());
     tellerArray[tellerNum].totalPeople++;
     tellerArray[tellerNum].available=false;
     tstTotCusts++;
      }
 
// ==========================================================================
  private static void clearTeller(int tellerNum){
     // calculate actual time, not just interval time
      long elapsedTime = System.currentTimeMillis() -
              tellerWindow[tellerNum].startTime;
                                            // get Customer address from array
      Customer finishedCust=tellerWindow[tellerNum];
      finishedCust.assignedPerson=0;            //  clear assigned person
//      finishedCustomers.enqueue(finishedCust);  // put in finished queue
      tstCustomersinFinishedQueue++;            // update total
//      tellerWindow[tellerNum]=null;              // clear array cell
      //  update total time for teller and set available flag
      tellerArray[tellerNum].timeOccupied+=elapsedTime;
      tellerArray[tellerNum].available=true;
      tellerWindow[tellerNum]= new Customer();  // assign empty customer object
      tstTotServed++;
  }
// =========================================================================
  private static int getRandomNum(int Min, int Max) {
    int intReturn = Min + (int)(Math.random() * ((Max - Min) + 1));
    return intReturn;
  }
// =========================================================================
 public static void endPrintout(){
    System.out.println("Total amount of customers that visited the bank is "+
           tstTotCusts );
    System.out.println("Total amount of customers for teller 1 is "+
           tellerArray[1].totalPeople);
    System.out.println("Total amount of time teller 1 was occupied is "+
         ((tellerArray[1].timeOccupied) / 1000) % 60);
    System.out.println("Total amount of customers for teller 2 is "+
           tellerArray[2].totalPeople);
    System.out.println("Total amount of time teller 2 was occupied is "+
         ((tellerArray[2].timeOccupied) / 1000) % 60);
    System.out.println("Total amount of customers for teller 3 is "+
           tellerArray[3].totalPeople);
    System.out.println("Total amount of time teller 3 was occupied is "+
         ((tellerArray[3].timeOccupied) / 1000) % 60);
    System.out.println("Total amount of customers for teller 4 is "+
           tellerArray[4].totalPeople);
    System.out.println("Total amount of time teller 4 was occupied is "+
         ((tellerArray[4].timeOccupied) / 1000) % 60);
    System.out.println("Total amount of customers for teller 5 is "+
           tellerArray[5].totalPeople);
    System.out.println("Total amount of time teller 5 was occupied is "+
         ((tellerArray[5].timeOccupied) / 1000) % 60);
    System.out.println("Total amount of customers left in queue is "+
            tstCustomersInQueue );
 }
// =========================================================================
public static class Teller  {

    private Boolean available;
    private int assignedPerson;
    private int totalPeople;
    private long timeOccupied;
    private int intervalTime;         // 1 second = 1000 millis()
    private long startTime;
    private long endTime;

// constructor
    public Teller() {
      available = true;
      intervalTime = 0;
      assignedPerson = 0;
      totalPeople = 0;
      timeOccupied=0;
      startTime = 0;
      endTime = 0;
    }

   // methods - obvious what they do so do not need individual comments
    public long getEndTime() {
      return endTime;
    }
 }

public static class Customer  {
    private Boolean available;
    private int assignedPerson;
    private int totalPeople;
    private long timeOccupied;
    private int intervalTime;         // 1 second = 1000 millis()
    private long startTime;
    private long endTime;
    private boolean empty;
// constructor
    //  create empty customer to fill tellerWindow if necessary
    public Customer() {
      available = true;
      intervalTime = 0;
      assignedPerson = 0;
      totalPeople = 0;
      timeOccupied=0;
      startTime = 0;
      endTime = 0;
      empty=true;
    }
    public Customer(int inTime) {
      available = true;
      intervalTime = inTime;
      assignedPerson = 0;
      totalPeople = 0;
      timeOccupied=0;
      startTime = 0;
      endTime = 0;
      empty=false;
    }

   // methods - obvious what they do so do not need individual comments
    public void setTeller(int i) {
       assignedPerson=i;
       available=false;
    }
    public void clearTeller(){
        assignedPerson=0;
        available=true;
    }
    public void setStartTime(long inTime){
        startTime=inTime;
        endTime=startTime+intervalTime;
    }
    public long getEndTime() {
      return endTime;
    }
 }
//  +++++++++++++++++++++++++++  borrowed code
// ArrayQueue class
//
// CONSTRUCTION: with no initializer
//
// ******************PUBLIC OPERATIONS*********************
// void enqueue( x )      --> Insert x
// Object getFront( )     --> Return least recently inserted item
// Object dequeue( )      --> Return and remove least recent item
// boolean isEmpty( )     --> Return true if empty; else false
// void makeEmpty( )      --> Remove all items
// ******************ERRORS********************************
// getFront or dequeue on empty queue

/**
 * Array-based implementation of the queue.
 */
public static class ArrayQueue implements Queue
{
    /**
     * Construct the queue.
     */
    public ArrayQueue( )
    {
        theArray = new Customer[ DEFAULT_CAPACITY ];
        makeEmpty( );
    }

    /**
     * Test if the queue is logically empty.
     * @return true if empty, false otherwise.
     */
    public boolean isEmpty( )
    {
        return currentSize == 0;
    }

    /**
     * Make the queue logically empty.
     */
    public void makeEmpty( )
    {
        currentSize = 0;
        front = 0;
        back = -1;
    }

    /**
     * Return and remove the least recently inserted item
     * from the queue.
     * @return the least recently inserted item in the queue.
     * @throws UnderflowException if the queue is empty.
     */
    public Customer dequeue( )
    {
        if( isEmpty( ) ) {
         waitCustQueueEmpty=true;
         Customer returnValue = new Customer();
         return returnValue;
        }
            //            new UnderflowException( "ArrayQueue dequeue" );
        currentSize--;

        Customer returnValue = theArray[ front ];
        front = increment( front );
        return returnValue;
    }

    /**
     * Get the least recently inserted item in the queue.
     * Does not alter the queue.
     * @return the least recently inserted item in the queue.
     * @throws UnderflowException if the queue is empty.
     */
    public Customer getFront( )
    {
        if( isEmpty( ) ) {
         waitCustQueueEmpty=true;
         Customer returnValue = new Customer();
         return returnValue;
        }
 //           throw new UnderflowException( "ArrayQueue getFront" );
        return theArray[ front ];
    }

    /**
     * Insert a new item into the queue.
     * @param x the item to insert.
     */
    public void enqueue( Customer x )
    {
        if( currentSize == theArray.length )
            doubleQueue( );
        back = increment( back );
        theArray[ back ] = x;
        currentSize++;
    }

    /**
     * Internal method to increment with wraparound.
     * @param x any index in theArray's range.
     * @return x+1, or 0 if x is at the end of theArray.
     */
    private int increment( int x )
    {
        if( ++x == theArray.length )
            x = 0;
        return x;
    }

    /**
     * Internal method to expand theArray.
     */
    private void doubleQueue( )
    {
        Customer [ ] newArray;

        newArray = new Customer[ theArray.length * 2 ];

            // Copy elements that are logically in the queue
        for( int i = 0; i < currentSize; i++, front = increment( front ) )
            newArray[ i ] = theArray[ front ];

        theArray = newArray;
        front = 0;
        back = currentSize - 1;
    }

    private Customer [ ] theArray;
    private int        currentSize;
    private int        front;
    private int        back;

    private static final int DEFAULT_CAPACITY = 12;


}

/**
 * Exception class for access in empty containers
 * such as stacks, queues, and priority queues.
 */
public static class UnderflowException extends RuntimeException
{
    /**
     * Construct this exception object.
     * @param message the error message.
     */
    public UnderflowException( String message )
    {
        super( message );
    }
}

// Queue interface
//
// ******************PUBLIC OPERATIONS*********************
// void enqueue( x )      --> Insert x
// Object getFront( )     --> Return least recently inserted item
// Object dequeue( )      --> Return and remove least recent item
// boolean isEmpty( )     --> Return true if empty; else false
// void makeEmpty( )      --> Remove all items
// ******************ERRORS********************************
// getFront or dequeue on empty queue

/**
 * Protocol for queues.
 */
public interface Queue
{
    /**
     * Insert a new item into the queue.
     * @param x the item to insert.
     */
    void  enqueue( Customer x );

    /**
     * Get the least recently inserted item in the queue.
     * Does not alter the queue.
     * @return the least recently inserted item in the queue.
     * @exception UnderflowException if the queue is empty.
     */
    Customer getFront( );

    /**
     * Return and remove the least recently inserted item
     * from the queue.
     * @return the least recently inserted item in the queue.
     * @exception UnderflowException if the queue is empty.
     */
    Customer dequeue( );

    /**
     * Test if the queue is logically empty.
     * @return true if empty, false otherwise.
     */
    boolean isEmpty( );

    /**
     * Make the queue logically empty.
     */
    void makeEmpty( );
}

}
ASKER CERTIFIED SOLUTION
Avatar of Pramod Kumar
Pramod Kumar
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of jjackson2004

ASKER

Question is where is the leak?
I can't quite see it but I see lots of possibilities.  Main causes of a memory leak are:
- a dynamic collection like an HashMap or an ArrayList (which usually underly queues). If you keep adding to them and never removing from them they will grow and grow until you run out of memory.
- creating objects that never get destroyed.  If you create a new object and your code holds a reference to it then it will continue to take up memory.  you may not be destroying all the new Customers that you are creating.
Avatar of a_b
a_b

What is the stack trace? Can you post that?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
The number of objects that you are creating in 12000ms is way more that the heap space. Hence the error. Try reducing the time.
the program is supposed to run for 2 minutes, that is why I have the starttime+120000,  120000 ms is supoosed to be 2 minutes.
how do you do a stack trace?
A new customer object is only supposed to be created every 2-6 seconds depending on the random number generating, yet I am getting 10million+ objects.
This condition will always hold true -

 long loopStartTime=System.currentTimeMillis();
    if (loopStartTime>nextCustomerTime){
        createCust();
    }

Therefore your customers are created continuously.
Another side note-

public static long currentTimeMillis()
Returns the current time in milliseconds. Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the underlying operating system and may be larger. For example, many operating systems measure time in units of tens of milliseconds.
Try -

int ctr = 0;
    while (System.currentTimeMillis() < startTime+12000){
//      long loopBeginTime= System.currentTimeMillis();
//          System.out.println(ctr++);
        nextCustomerTime=startTime+getRandomNum(2,6)*1000000; -> The multiplication factor might differ
      bankLoop();
      tstTime = System.currentTimeMillis();

    }
Change - 1000000 to 1000. Atleast you will not run into the heap space error.
Try -
while (System.currentTimeMillis() < startTime+12000){
//      long loopBeginTime= System.currentTimeMillis();
//          System.out.println(ctr++);
          try
          {
                Thread.sleep(getRandomNum(2,6)*1000);
          }
          catch(Exception e)
          {
                
          }
//        nextCustomerTime=tstTime+getRandomNum(2,6)*1000;
      bankLoop();
      tstTime = System.currentTimeMillis();

    }


and

  private static void bankLoop(){
    long loopStartTime=System.currentTimeMillis();
//    if (loopStartTime>nextCustomerTime){
       
          createCust();
//    }
The problem with this last code you sent is that it ignores the teller activity that is supposed to be taking place while the new customer delay is going on.

Maybe you could show me how I could make the tellers async threads, or how I might use the timer class to create autonomous tellers.

Thanks in advance
As to the loop always being true

    nextCustomerTime=startTime+(getRandomNum(2,6)*1000);

this code is supposed to be adding 2-6 seconds to the loopstart time.  I assumed the loop would be occurring in the milliseconds range and would not take 2-6 seconds to get through.
Can you explain to me what the program is doing? I would be able to better advise you then.
from an earlier thread:

my scenario is that the life of this program is a 2 minute period.  Basically, it is a bank scenario. for 2 minutes,  I generate a customer at a random 2-6 sec interval and queue them up.  Have 5 tellers which I will just use class objects for.  A customer will be with each teller for 2-5 secs (random generated).  Time up and a new customer is taken from the queue and put with that teller.  At end of two mins I will flush the queue and print results.  
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
How does one do threads?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you for your assistance.  This question is now moot.  I divided up points to those who helped.