18

When developing an Android app in Android Studio, a variable used within a while loop has an incorrect value. I reduced it in a test case to a very simple case:

  1. Create a new project in Android Studio, blank Activity
  2. Add the following code to the main activity

method onStart:

@Override
public void onStart() {
    super.onStart();

    int count = 2;
    int index = 1;

    int value = 23;

    Log.i("test", "value before = " + value);
    while (index < count) {
        Log.i("test", "value in while loop = " + value);
        index++;
        value = 0;
    }
}

The output when executing the test app is:

value before = 23
value in while loop = 0

while the result should be

value in while loop = 23

When debugging, the result is as expected ('value in while loop = 23'), but in a regular debug build, it is wrong. The disassembled code of the main activity class looks ok, the value of the variable 'value' is set to 0 at the end of the while loop body. When some code or a function within the while loop body uses the variable 'value' it will have the value 0 instead of 23. In the test case I use the Log statement to simplify.

It doesn't go wrong when I change the line

value = 0;

to

if (value == 23) {
    value = 0;
}

or when I remove the line

value = 0; 

So it looks like some optimization error. But what optimization is done that could cause this? It makes the code unreliable.

zapl
  • 63,179
  • 10
  • 123
  • 154
Hielko
  • 243
  • 1
  • 10
  • 1
    It really depends on your specific Java version and - most importantly - specific JVM. But yes, Java does optimization, the JVM does runtimetime optimization, and loop unrolling can be among the optimizations. For example, look here: [Java JIT loop unrolling policy?](http://stackoverflow.com/questions/7243221/java-jit-loop-unrolling-policy). – paulsm4 Nov 23 '15 at 20:41
  • So it looks as if actually using the value for anything will stop the optimizer from changing the value. Curious that the Log statement does not seem to count. – mjstam Nov 23 '15 at 21:08
  • I wouldn't characterize it as either an "error" or "code unreliability". Optimization is a Good Thing. Which, if needed, you can control with compiler and/or JVM switches. Also - it's definitely a Good Thing that the log shows you what's *ACTUALLY HAPPENING* (vs. "what I think should be happening") at runtime. IMHO... – paulsm4 Nov 23 '15 at 21:12
  • 2
    @paulsm4 it is an **illegal optimization** to change to output of code from 23 to 0. What needs to happen is well defined. You can trace the code on paper and you'll see that 23 is the only value you can print there. Reordering instructions is only allowed as long as no observable effect results from that. – zapl Nov 23 '15 at 21:15
  • "When some code or a function within the while loop body uses the variable 'value' it will have the value 0 instead of 23." So what value should the variable have in the while loop? – Sebastian Walla Nov 23 '15 at 21:18
  • @Sebastian Walla There is only one iteration in the loop. The value of variable 'value' should be 23, because it is only set to 0 at the end of the while loop body. It shouldn't become 0 before the end of the first (and only) iteration. In the real app it took me a long time to find out what was going wrong. – Hielko Nov 23 '15 at 21:22
  • @zapl yes, I test it on a Samsung. What does this imply? – Hielko Nov 23 '15 at 21:23
  • 1
    Idk, but I've seen this before, exclusively on Samsung Galaxy S5s or so. No other device was affected. I guess samsung messed up on of their optimizations. I never got around to investigate further because I had no phone of that type to test (just several play store bug reports) – zapl Nov 23 '15 at 21:24
  • As a workaround can use use a for loop instead? If the optimization is incorrect on certain devices such as Samsung Galaxy S5s, perhaps a for loop will work correctly. I would try both a traditional for loop, and a for loop using the for : each syntax. – joshgoldeneagle Nov 23 '15 at 21:35
  • 1
    @joshgoldeneagle I checked the for loop, it has the same problem. There are work-arounds, that's not the problem. But the problem is that the issue is harming the normal execution flow and that is very dangerous because you don't expect it. – Hielko Nov 23 '15 at 21:45
  • https://gist.github.com/anonymous/c2ed331804b821fd3316 was my issue, the value of the variable was taken as if it was after the first loop. May or may not be related to constant values after each iteration loop. If so, that would be kind of avoidable but it's obviously not a great solution – zapl Nov 23 '15 at 21:55
  • Can you change the log and show us the result `Log.i("test", "value in while loop = " + value + " + " +index +" + "+ count);` – NamNH Nov 24 '15 at 03:39
  • 1
    Thanks for all the comments. With the example of @zapl it is confirmed that there is a real optimization error, at least in some Samsung phones. The execution flow should never be changed in such a way that the semantics of the code is changed, when an optimization is performed. **If someone knows how to contact Samsung about this**, then please let me know. – Hielko Nov 24 '15 at 19:51
  • If you can confirm the issue is not limited to Samsung, you should report it to the Android developers. Intuitively, I'd be surprised that the issue is Samsung specific, though I suppose it's possible they'd make low-level modifications to the Android JVM that impact compiler optimizations. – dimo414 Dec 01 '15 at 03:33
  • @Hielko out of curiosity, is Power Saving on? Can you try with it on or off? – petey Jan 17 '16 at 01:21
  • Power Saving was not on. I don't have the code available anymore (created a work around), so I won't test it in Power Saving off mode now, it won't help solve the problem I think. – Hielko Jan 17 '16 at 11:15
  • Log is expensive since its an I/O operation compared to while loop. This won't happen in usual case. Theoretically it should not happen since 'value' object is associated with Log. I don't see any reason to skip that Log statement either. – shijin Aug 03 '16 at 13:25
  • So it is probably a too radical optimisation of the Dalvik code / unsafe real machine code. As mentioned out-of-order execution is handled carefully on the JVM side. – Joop Eggen Nov 12 '19 at 09:47

2 Answers2

1

If you are really sure that the written code works correctly then from now on, you must start to check (ordered):

  • configuration --> is your project configuration totally ok with Java versions, jdks or the Java version is compatible with used Android libraries? Are your Java and Andorid libraries correctly configured?
  • environment --> is your debugging emulator a 3rd party library or is your debugging device is a valid device to debug your code? Is your coding OS is compatible with your ide, Java version or Android libraries?
  • JVM --> Did you try uninstalling and reinstalling with the correct source for Java jdk with the version you are using?

Maybe you must give some details about your environment like Java version, Android min version, OS or the IDE you are using.

I hope those bullets will make you some correct associations to resolve your problem.

Bahadir Tasdemir
  • 10,325
  • 4
  • 49
  • 61
0

I cannot reproduce the example. I am getting always (both run and debug configurations):

value before = 23
value in while loop = 23

I just created a new project in my Android Studio and compiled it using the SDK version 28. Then I just ran the project in the emulator (with API 26) and everything worked as expected.

pglez82
  • 489
  • 5
  • 11