Well scoped variables each draw vs global variables

I understand the difference between global variables and locally-scoped variables each draw.

If I’m going to use a variable only inside draw (or keyPressed, or any function), good programming practice dictates that it is scoped locally. I also prefer it because everything can be neatly organised where it’s needed.

Am I incurring in some significant performance drawback by using locally-scoped variables, or is processing/Java smart enough to not allocate each draw? Notice there are two parts to the question: even if variables are allocated each draw, I’d like to know if the performance impact is negligible.

Edit: I’ve removed the examples because even though I specifically asked to not discuss them as they were just crude representations, answers are fixating on them instead of the question.

I would not count on processing to be smart enough to allocate it only once. In processing (and usually in graphic programming) not every programming practice is good, because some of them really have an impact on performance.

Here it is not recommended to have the PGraphics inside of the draw, but it also does not make sense to create the graphics inside the draw. Try to put everything that has to run once into the setup() method, and everything which has to run 60 times per second into the draw method.

The correct way would be:

PGraphics pg;

void setup() {
  size(100, 200);
  pg = createGraphics(someNumber, someNumber);
}

void draw() {
  int someNumber = 10;
  // work with pg
}

I specifically said

I know the “correct” method and understand there may be an impact on performance. My question is if said impact makes a significant difference.

I thought my answer implies that it makes a significant difference. In a real project where you are counting every ms which is lost by something, it makes a significant difference. If you have enough resources, it won’t make a significant difference of course.

But the real big performance problem you will have is the creation of your offscreen canvas (as I wrote). Start a profiler and profile your sketch, there you will see the significant difference. GC is turning mad :wink:

With createGraphics inside draw():

Without:

Thank you for the profiling graphics, but that still does not answer the question because once again you’re getting hung up on my examples instead of my question. My question is about defining variables. Variable scope, not variable use. createGraphics is function, not a variable; I don’t care about it’s performance.

What I care about is the performance of PGraphics pg or int someNumber = 10.

@cuI6QV0SphbBeN9E yes, your question is asking whether storing something in a local variable is more expensive than storing it globally. No, not really, a good chance it’s less expensive in fact.

On the other hand, your code is asking whether calling really-expensive-method (or allocating lots of memory) many times a second is more expensive than calling really-expensive-method once. Er, yes, of course it is. :wink:

Could you explain further? My worry is that the repeated int or PGraphics operations will have an impact. I can understand if there’s a small negative impact, but you’re claiming the impact may even be positive. Why? Shouldn’t doing the operation over and over (even if locally) be more resource intensive than doing it once (even if globally)?

Not really. Since the createGraphics is in draw in both examples, it should be assumed it needs to be there. That’s why I asked to not discuss the examples specifically — what matters are the differences between them.

I would recommend to compile both versions, and then compare the bytecode :slight_smile:

You can’t remove how expensive the allocation is (eg. createGraphics() ), or whether you need the value (eg. object reference) to be stable across calls to draw() from consideration in answering this question.

But with eg. int someNumber = 10 this might be faster locally due to the way the JIT compiler can optimise, no need to care about heap memory, etc. So value types (int, boolean, float, etc.) being allocated like that (particularly to a constant) might be faster, assuming the code to allocate the value is light!

Lightweight objects (like PVector) might even be faster calling new once per draw, because the object allocation may never happen - google “Java escape analysis” (and don’t profile it with VisualVM!). Heavyweight objects (like PGraphics) should almost always be cached in a field, and in the case where you’re allocating one per draw() just cleared and reused.

Your question is simply not answerable without knowing what the type of the field is, how expensive the allocation code is, and whether the value needs to remain across calls.

That link doesn’t show what you claim it does! :wink: That’s comparing local variables inside and outside a block rather than field allocation. I strongly suspect you’ll find different bytecode then!

1 Like

“Escape Analysis” doesn’t magically make a memory block allocation not to happen! :roll_eyes:

Actually, it doesn’t make the allocation any faster either! :no_mouth:

Whether an object is created in the heap or in the stack won’t change the time it takes to allocate some contiguous block of memory in order to store it. :face_with_monocle:

The only diff. is that an object created in the stack is gone when its stack dies. No GC needed at all. :muscle:

Therefore, if we need a PVector object over & over, we’re better off instantiating it once & storing it in some global field, rather than re-creating it locally each time we call a function. :nerd_face:

We can “refresh” the PVector’s 3 float fields (x, y & z) by calling its set() method: :cowboy_hat_face:

Don’t roll your eyes at me! :smile: I said object allocation, which is exactly what escape analysis gets rid of! It allocates the memory for the object fields directly on the stack.

Allocation, de-allocation, reading and writing on the stack are all likely to be faster. So, there’s a good chance using a new PVector locally will end up faster than a global PVector once escape analysis kicks in. It’s a good fit for allocating once per draw() at least. EDIT: actually, using new PVector() in a tight loop should allocate on the stack only once if EA kicks in.

And it’s all premature optimization. Use globals when you need the semantics of stored state or the object is expensive to create, otherwise use locals. Write readable code before worrying about performance.

That’s part of my reason for opening the question. It’s customary in Processing to have these as global variables, but I’d rather write good readable code unless the performance takes a significant hit.