Memory leak when use newInsance() method - java

I have the following method with the for loops. I'm concern about the memory leaking by doing that.
My question: For every loop in for loops, Is that true that newInstance() method will allocate new memory block? If that so, should I create a VehicleImpl Instance before step into the for loop and try to set new values for this VehicleImpl Instance.
private List<VehicleImpl> setVehicles(JsonInput input) {
List<VehicleImpl> vehicles = new ArrayList<VehicleImpl>();
Break lunch = Break.Builder.newInstance("Lunch")
//timewindow(start time, end time), so lunch timewindow(start, start + duration)
.setTimeWindow(TimeWindow.newInstance(input.getLunch().getStart(),
input.getLunch().getStart() + input.getLunch().getDuration()))
//Lunch has highest priority
.setPriority(1)
//Lunch takes serviceTime
.setServiceTime(input.getLunch().getDuration())
.build();
VehicleType type = VehicleTypeImpl.Builder.newInstance("vehicleType")
.setCostPerDistance(input.getCosts().getCostPerMeter())
.setCostPerTransportTime(input.getCosts().getCostPerTransportSecond())
.setCostPerServiceTime(input.getCosts().getCostPerServiceTime())
.build();
for(int i = 0; i < input.getNoVehicles(); i++) {
//Name vehicle by index
VehicleImpl vehicle = VehicleImpl.Builder.newInstance("vehicle " + String.valueOf(i+1))
//The first location - depot location is indexed as 0 in Matrices
.setStartLocation(Location.newInstance(i))
.setBreak(lunch)
.setLatestArrival(input.getOperating())
.setType(type)
.build();
vehicles.add(vehicle);
}
return vehicles;
}

There is no leaking memory here. There is just a temporary reference variable that is created and destroyed in each iteration of the for loop. You can avoid that by declaring that variable before the for loop.

Related

Java code optimization, Heap size constraint (use less memory)

I am facing of memory exception while running this code and the constraint is heap size. Can anyone suggest if there is a way to optimize this code further?
public class getCustomerList {
public static List <Customer> retrieve() throws ParseException {
List<Customer> customers = new ArrayList<Customer>();
for (int i = 0; i < 100000; i++) {
Customer customer = new Customer();
customer.setAge(new Integer(i));
customer.setBirthDate((new SimpleDateFormat("ddMMyyyy")).parse("01061986"));
customer.setName("Customer" + new String((new Integer(i)).toString()));
customers.add(customer);
}
return customers;
}
}
Few ideas that might help:
Make age primitive, if it already is, provide the method an int, not Integer.
customer.setAge(i);
Move SimpleDateFormat outside the loop, currently you create 100000 same instances.
customer.setBirthDate(format.parse("01061986"));
Do you really need 100000 same Date instances for every customer? If you don't, you can get away with setting the same date instance in every customer.
customer.setBirthDate(date);
Current name creation is very inefficient, you create Integer object, then create string from it(and the integer is thrown away), then create copy of said string(and throw away the initial one). Just do:
customer.setName("Customer" + i);

compare three variables and get the variable with min/max value back (not value)

I have 3 variables with long values timestamp1 timestamp2 timestamp3 and an arraylist timestampList. I want to compare them in an if/else. It could be possible, that the three timestamps have different values, so I want to add the values with the min value to the list. I should also mention, that these timestamps are coming in every 2 minutes.
When the three variables are same, I could simply do
if(timestamp1 == timestamp2 && timestamp2 == timestamp3){
timestampList.add(timestamp 1); //since they are the same it doesn't matter which i add to the list
.
.
.
}
now in the else or else if I want to check the three timestamps and get the variable with the min value, not the value itself. Because I need the variable for other variables further in the code. Of course I also want to add the min value to the list too. I can imagine, that I could do more if/else branches in the else like
else{
if(timestamp1 < timestamp2){
if(timestamp1 < timestamp3){
...
}else{
...
}
}
}
but that would be too much and there is certainly a better way.
Try this:
long timestamp1 = 1;
long timestamp2 = 2;
long timestamp3 = 3;
long result = LongStream.of(timestamp1, timestamp2, timestamp3)
.min()
.getAsLong();
You can not really get a "pointer" to a variable in Java, as you could in C. The closest thing would be using a mutable type instead, so instead of assigning a new value to the variable you can modify an attribute of the existing instance, and the change will be reflected anywhere else in your code where you have a reference to that instance.
For example, you could wrap your long timestamps into AtomicLong instances:
// wrap in mutable AtomicLong instances
AtomicLong timestamp1 = new AtomicLong(123);
AtomicLong timestamp2 = new AtomicLong(456);
AtomicLong timestamp3 = new AtomicLong(789);
// get minimum or maximum, using streams or any other way
AtomicLong minTimeStamp = Stream.of(timestamp1, timestamp2, timestamp3)
.min(Comparator.comparing(AtomicLong::get)).get();
// modify value
System.out.println(minTimeStamp); // 123
timestamp1.set(1000); // change original variable
System.out.println(minTimeStamp); // 1000
Another way to keep a variable to a certain value would be to use Optional<Long> as #tobias_k mentioned in his comment. An alternative to Stream would be to use a TreeSet. When creating the TreeSet we provide the Function to compare the elements. After all timestamps has been added, we can call TreeSet.first() to get the minimum element.
List<Optional<Long>> timestamps = Arrays.asList(Optional.of(1234l), Optional.of(2345l), Optional.of(1234l));
TreeSet<Optional<Long>> setOfTimestamps = new TreeSet<>(Comparator.comparing(Optional::get));
setOfTimestamps.addAll(timestamps);
Optional<Long> min = setOfTimestamps.first();
System.out.println(min.get());
So I went with the idea of #Amadan and created an array with the timestamps. But after thinking a little bit, I came to the conclusion that it would be possible without getting the variable.
long[] arrayDo = new long[3];
arrayDo[0] = eafedo5.getServiceInformation(eafedo5Count).getTimestamp();
arrayDo[1] = eafedo6.getServiceInformation(eafedo6Count).getTimestamp();
arrayDo[2] = eafedo7.getServiceInformation(eafedo7Count).getTimestamp();
Then I calculate the minValue of the array.
long minTimestamp = Math.min(arrayDo[0],Math.min(arrayDo[1],arrayDo[2]));
Then I ask if the timestamps are equal to minValue
if(!timestamps.contains(minTimestamp)){
timestamps.add(minTimestamp);
}
if(eafedo5.getServiceInformation(eafedo5Count).getTimestamp() ==minTimestamp){
for(CHostNeighbor n : hostNeighborsEafedo5){
msgsCountDo += n.getInboundMsgs();
}
eafedo5Count--;
}
if(eafedo6.getServiceInformation(eafedo6Count).getTimestamp() ==minTimestamp){
for(CHostNeighbor n : hostNeighborsEafedo6){
msgsCountDo += n.getInboundMsgs();
}
eafedo6Count--;
}
if(eafedo7.getServiceInformation(eafedo7Count).getTimestamp() ==minTimestamp){
for(CHostNeighbor n : hostNeighborsEafedo7){
msgsCountDo += n.getInboundMsgs();
}
eafedo7Count--;
}
msgsDo.add(msgsCountDo);
I mentioned in my question that I need the variable for later purposes. It was because I needed the name of the variable to decrement the count variable of the specific host. (the eafed... are hosts).
Thanks for all the answers!

Will this work like a destructor?

I am working on a Processing program for Brownian motion tracking.
I have an ArrayList blobs and ArrayList tomerge. The first one is a list of particles which I track and the second one is a list of particles which I want to merge.
Every particle is a Blob class object. Blob object countains ArrayList of Vectors called lespoints and int id in its data.
Since I need to merge a few particles in one, I need to destroy some Blob objects, but Java doesn't have any destructors and I don't want to use finalise(). Will this work like merge + destruction?
public void delete(Blob a)
{
a = null;
}
void merge(ArrayList<Blob> tomerge)
{
int i = 0;
int j = 0;
while (i <= tomerge.size())
{
Blob k = new Blob();
k = tomerge.get(i);
while (j <= tomerge.get(i).siz()) {
Vector g = k.lespoints.get(j);
lespoints.add(g);
j++;
}
if (i > 0)
{
delete(tomerge.get(i));
}
i++;
}
}
You don't need to manually do anything. Just make sure you don't have any references to the variables you want to go away, and Java will handle the rest.
For example:
String x = "test";
x = null;
At this point, the value "test" can be garbage collected because nothing points to it.
Compare that to this:
String x = "test";
ArrayList<String> list = new ArrayList<>();
list.add(x);
x = null;
At this point, the value "test" cannot be garabage collected, because the ArrayList still points to it.
But if you did this:
list.remove("test");
Then it could be garbage collected.
So basically, all you need to do is remove the element from your ArrayList and Java will take care of the rest. Note that you probably don't want to do this in your current loop, as removing elements while you iterate over a list can cause you to skip over elements.
Instead, you probably want to use an iterator or just loop backwards over your ArrayList.
Shameless self-promotion: here is a tutorial on ArrayLists, including removing elements from them.
There is an exact reason why your code example won't work.
public void delete(Blob a)
{
a = null;
}
Blob b = new Blob();
delete(b);
In this code example, the reference which is set to null is a, not b.
You are not deleting the Blob object, you are setting the reference to null.
When the delete() method is called, there exists 2 references to the Blob.
One reference is b, which is in the calling code.
The other reference is a, which is in the called code.
a is set to null, and then the method exits. But the b reference continues to exist throughout. Therefore the Blob will never be garbage-collected.
To achieve garbage-collection, you must remove all references to an object; then it gets destructed at the JVM's convenience.
The Java Collections API for removing an object during iteration works like this:
Iterator<Blob> itr = list.iterator();
while( itr.hasNext() ) {
Blob b = itr.next();
if( /* test condition */ ) {
itr.remove(); // Safely removes object from List during iteration
}
} // Object `b` goes out of scope, and so this Blob is "lost" to the the code and is going to be destroyed

Add many element into list without instantiate too many object

I have a for loop like and an ArrayList as follow:
List<VehicleImpl> vehicles = new ArrayList<VehicleImpl>();
for(int i = 0; i < input.getNoVehicles(); i++) {
//Name vehicle by index
VehicleImpl vehicle = VehicleImpl.Builder.newInstance("vehicle " + String.valueOf(i+1))
//The first location - depot location is indexed as 0 in Matrices
.setStartLocation(Location.newInstance(i))
.setBreak(lunch)
.setLatestArrival(input.getOperating())
.setType(type)
.build();
vehicles.add(vehicle);
}
So, I want to ask: Is there any way I instantiate the VehicleImpl outside the loop and use the ONLY ONE instance. For each iteration, I modify the instance add the new version of instance to the list.
Yes but you have to clone the first intance at leat (By using BeanUtils for example).
Then you just update the startLocation attribute.
You could instantiate the builder outside the loop, which would halve the number of objects you're creating, but only if you were to change the builder's constructor to have zero arguments, moving the vehicle name into a setter. For example:
List<VehicleImpl> vehicles = new ArrayList<VehicleImpl>();
VehicleImpl.Builder builder = VehicleImpl.Builder.newInstance();
for(int i = 0; i < input.getNoVehicles(); i++) {
VehicleImpl vehicle = builder
//Name vehicle by index
.setName("vehicle " + String.valueOf(i+1))
//The first location - depot location is indexed as 0 in Matrices
.setStartLocation(Location.newInstance(i))
.setBreak(lunch)
.setLatestArrival(input.getOperating())
.setType(type)
.build();
vehicles.add(vehicle);
}
This is somewhat more error prone because values in the builder are not reset on each new iteration. That's not necessarily a problem for you right now, but if you were to add conditional logic, you'd probably start having a lot of problems. However, if your goal is to reduce the number of objects created, this will satisfy that.

Creating multiple objects using a for loop

I'm having difficulty in creating multiple objects in a for loop the object keeps being overwritten each time the loop is run.
for(i = 0 ; i < 10; i++){
Driver one = new Driver();
}
How do I make it so that new objects are created every time the loop is run, currently one just keeps being overwritten.
Sorry for the basic question i'm just new to programming.
You can do this using array:
int n = 10;
Driver[] driverArray = new Driver[n];
for(int i = 0 ; i < n; i++){
driverArray[i]= new Driver();
}
In your code, you are declaring a local reference to Driver class, and creating new Driver object in every iteration.
It doesn't work for two reasons:
1. You are declaring local reference in for-loop so the only place, when you can use it is this for-loop.
2. Even if you declare the reference outside the loop you would initialize it with new Driver object so after loop you would have the only one Driver insance - the last one.
For more about arrays you can read here.
Hope it helps.

Categories