質問

I know many people have asked this question before but my focus isn't on performance but rather the memory footprint of the operation.

Consider the following dummy class:

public class MemoryDemo implements Runnable{

    private boolean run;

    public MemoryDemo(){
        run = true;
    }

    @Override
    public void run(){
        byte[] wbuffer; //Here

        final int n = ... //Some big quantity in order of millions.


        while(run){
            //byte[] wbuffer; or here?

            wbuffer = new byte[n]; //Reallocate every loop? or just keep the same memory?

            //Do stuff with the byte array here

            //Copies the data to the target buffer (Not shown here, from another class)
            System.arraycopy(wbuffer, 0, n, targetbuffer, 0, wbuffer.length);
        }
    }
}

I know from here and here people have said it makes absolutely no difference performance-wise and that limited scope is the better approach but what about memory footprint?

If you observe from above you can see I'm allocating some pretty large arrays and since java has no delete function/construct we have to rely on the garbage collector to free the memory. In my application I have several of these loops (its basically a realtime image processing pipeline) I'm looking to minimize memory footprint as much as possible (i.e help GC to do its job in the best way it can).

Which, inside the loop or outside the loop declaration, if any, is better in terms of garbage collection? I know GC can only free memory if there is no longer a reference to it but I'm unclear what happens if you reassign a variable (i.e When the loop restarts and the wbuffer object gets assigned again). Since the inside loop variable loses its whole reference does it get garbage collected first? Or do they both get garbage collected when the variable gets reassigned? Should I call System.gc(); at the end of every loop?

Also, what if I never reassign the variable (as in I never call new byte[n] within the loop) assuming my code can write to all bytes in the byte array, is not reallocating the byte array a better approach (a more ugly one too...)?

N.B Not reallocating the array may not be a viable option for me (for all my classes) if it does turn out to be the best option, please also explain which is the second best (inside/outside loop or no difference)!

役に立ちましたか?

解決

What matters from a memory perspective is to determine when the object becomes eligible for garbage collection.

In your case it makes no difference: as soon as you write wbuffer = new byte[n]; the previous byte array becomes unreachable and therefore eligible for GC.

Reusing the same array would improve memory footprint in which case you need to declare it before the loop.

And GC will run when necessary. Apart from very specific use cases, it is generally a bad idea to call System.gc(); - it can actually have a negative impact on performance.

他のヒント

You have misunderstood the questions you link to.

In these questions, the issue was were the variable was defined, but the number of objects allocated did not change. So, it did not affect performance.

But between

byte[] wbuffer = new byte[size];
for (....) {
}

and

for (....) {
   byte[] wbuffer = new byte[size];
}

THERE ARE memory and performance differences.

Many more objects are created in the second one, which takes both a performance and memory hit.

The questions that you searched explain that there is no difference between the second form and

byte[] wbuffer;
for (...) {
   wbuffer = new byte[size];
}

Whether you declare byte[] wbuffer; inside or outside the loop it wont make much difference as its just a reference variable.

Main memory allocation happens here wbuffer = new byte[n]; , now if you create new array in every loop iteration then GC will be high for sure.

If somehow you can use same array in every loop iteration then definitely you will save memory otherwise no real difference will be there in performance even if you shuffle things here and there.

You shouldn't reallocate every loop. And you shouldn't Run the garbage Collection every time.

But actually it makes no Big differente.

The JVM's garbage collection is entirely unpredictable. Different implementations may perform differently, and Oracle's JVM alone has multiple garbage collector strategies.

Fortunately, you're working with a primitive array. This makes things considerably less complicated. If you only call new once, only one array is ever created. Editing values in the array, even if by System.arrayCopy, actually edits those values rather than making new arrays. If you declare the array outside the loop, the garbage collection doesn't even enter into the equation.

Makes no sense whether you put the declaration variable inside or outside the loop because you reassign it on every iteration. May be in this case you require a clean zero initialized array of bytes, so making it outside the loop makes sense only if you not reuse the same byte array.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top