Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unpredictable value when converting byte array to int | Eclipse Temurin-17.0.10+11 #1209

Open
1 task
ameys2907 opened this issue Dec 24, 2024 · 5 comments
Open
1 task
Labels
bug Something isn't working Waiting on OP

Comments

@ameys2907
Copy link

ameys2907 commented Dec 24, 2024

Please provide a brief summary of the bug

Problem Description:

I am encountering an issue when running the following multi-threaded program. The program spawns a large number of threads (10,000) that process the same byte array value. The issue becomes more frequent under high CPU usage and when memory constraints are applied (e.g., setting -Xms32m -Xmx32m).

The method byteArrayToInt is supposed to convert a specific segment of the byte array into an integer. However, intermittently, it produces incorrect values. The expected value for liVersion is 1, but random values are being observed instead. This issue occurs even when the program is executed with sufficient memory and less number of threads (even single thread) but becomes significantly less frequent.

The integer conversion of 2nd to 4th value of pTestData which is [1, 0] should be 1, but it intermittently gives random values in the output.

Environment:

Operating system: Windows 10

Java version: Eclipse Temurin-17.0.10+11

Code snippet:

import java.util.Arrays;

public class TestMain
{
	private static int miParallelThreadCount = 10000;

        private static long mlExecutionIntervalInMillis=100;
	    
	public static void main(String[] args)
	{
		System.out.println("Startin tornado at interval: " + mlExecutionIntervalInMillis + " with parallel threads: " + miParallelThreadCount);
		while(true)
		{
                        //Runs the test code to reproduce the issue
			runTornado();
			try
			{
				Thread.sleep(mlExecutionIntervalInMillis);
			} catch (Throwable lThrowable)
			{
				System.out.println("Task failed due to: " + lThrowable.getLocalizedMessage());
    	    	lThrowable.printStackTrace();
			}
		}
	}

    private static void runTornado() 
    { 	
        //Test byte array
    	byte[] data = new byte[]
    			{ 65, 50, 1, 0, 1, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 16, 0, 53, -76, -66, 125, -115, 69, -111, 80, -81, -33, -62, 84, -59, -64, -114, 113, -92, -59, 37, 106, 85, -111, -100, -19, 114, 99, 18, -9, -62, -123, -75, -22, -40, 70, -70, -46, 119, 11, -17, -71, -93, -126, -28, 116, 104, -4, -45, -58, 121, 4, 50, 76, 46, 13, -91, -76, 37, -103, 101, 57, 54, 75, 83, -124 };
    	
    	for(int i=0; i<miParallelThreadCount; ++i)
        {
                //This snippet executes the group of compareInner methods in new threads
    		new Thread(() -> 
            {
            	try
            	{
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
            		compareInner(data, 0, data.length);
        	    } 
        	    catch (Throwable lThrowable) 
        	    {
        	    	System.out.println("Something went wrong: " + lThrowable.getLocalizedMessage());
        	    	lThrowable.printStackTrace();
        	    }
            }).start();
        }
    	System.out.println("Ran tornado");
    }

	private static byte[] compareInner(byte[] pTestData, int pStartIndex, int pLength)
	{
                //Copies the pTestData into new array as it is
		byte[] lbarrData = Arrays.copyOfRange(pTestData, 0, 0 + pTestData.length);
               //copies only 2ndand 3rd element from the array which is [1, 0]
		byte[] lbarrVer = Arrays.copyOfRange(lbarrData, 2, 4);

               //Converts the array [1, 0] into integer, which should always return 1
		int liVersion = byteArrayToInt(lbarrVer);

		if(liVersion != 1)
		{
			System.out.println("Invalid Version : " + liVersion + " data array: " + Arrays.toString(lbarrData) +  " header array: " + Arrays.toString(lbarrVer));
		}
		
		return lbarrData;
	}
	
	public static final int byteArrayToInt(byte[] pSource)
	{
		int lValue = 0;
		for (int i = 0; i < pSource.length; i++)
		{
			lValue += (pSource[i] & 0xff) << (8 * i);
		}
		return lValue;
	}
}

Further analysis:

  • I tried running this code with 32m xms and xmx, issue is reproducible.
  • Issue is reproducible even when xms and xmx is 1024 but less frequent.
  • Issue is seen in single thread (miParallelThreadCount = 1) but is less frequent.
  • Issue has not been observed when taken a debug on the code.
  • Issue is not observed when a "compareInner(enc, 0, enc.length);" method is called only once per thread execution.

Did you test with the latest update version?

  • Yes

Please provide steps to reproduce where possible

No response

Expected Results

Startin tornado at interval: 100 with parallel threads: 10000
(Nothing will be in output except the starting line since the liVersion is 1)

Actual Results

Startin tornado at interval: 100 with parallel threads: 10000
Invalid Version : 50 data array: [65, 50, 1, 0, 1, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 16, 0, 53, -76, -66, 125, -115, 69, -111, 80, -81, -33, -62, 84, -59, -64, -114, 113, -92, -59, 37, 106, 85, -111, -100, -19, 114, 99, 18, -9, -62, -123, -75, -22, -40, 70, -70, -46, 119, 11, -17, -71, -93, -126, -28, 116, 104, -4, -45, -58, 121, 4, 50, 76, 46, 13, -91, -76, 37, -103, 101, 57, 54, 75, 83, -124] header array: [1, 0]

What Java Version are you using?

openjdk 17.0.10 2024-01-16 OpenJDK Runtime Environment Temurin-17.0.10+7 (build 17.0.10+7) OpenJDK 64-Bit Server VM Temurin-17.0.10+7 (build 17.0.10+7, mixed mode, sharing)

What is your operating system and platform?

Windows 10, 64-bit operating system, x64-based processor.

How did you install Java?

Manually placed the java zip and added JAVA_HOME and path in system variable.

Did it work before?

No response

Did you test with other Java versions?

Yes, with AdoptOpenJDK 11.0.11 and the issue has not been observed yet.

Relevant log output

Startin tornado at interval: 100 with parallel threads: 10000
Invalid Version : 50 data array: [65, 50, 1, 0, 1, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 16, 0, 53, -76, -66, 125, -115, 69, -111, 80, -81, -33, -62, 84, -59, -64, -114, 113, -92, -59, 37, 106, 85, -111, -100, -19, 114, 99, 18, -9, -62, -123, -75, -22, -40, 70, -70, -46, 119, 11, -17, -71, -93, -126, -28, 116, 104, -4, -45, -58, 121, 4, 50, 76, 46, 13, -91, -76, 37, -103, 101, 57, 54, 75, 83, -124] header array: [1, 0]
@ameys2907 ameys2907 added the bug Something isn't working label Dec 24, 2024
@karianna
Copy link
Contributor

please try 17.0.13 and report back

@ameys2907
Copy link
Author

Yes, i’m able to reproduce it on 17.0.13 as well.

@ameys2907 ameys2907 changed the title Unpredictable value when converting byte array to int | AdoptOpenJDK 17.0.10 Unpredictable value when converting byte array to int | Eclipse Temurin-17.0.10+11 Dec 27, 2024
@karianna
Copy link
Contributor

can you please post the full log for 17.0.13 (pathways might be different).

@ameys2907
Copy link
Author

can you please post the full log for 17.0.13 (pathways might be different).

Hi please find the below image with the java version and logs of the code snippet:
image

@karianna
Copy link
Contributor

karianna commented Jan 1, 2025

So I think you're running across a limit of what the JVBM supports with this programming model:

The runTornado method creates a massive number of threads (miParallelThreadCount), each running tasks that are CPU-intensive. With miParallelThreadCount set to 10000, this can overwhelm the thread scheduler, leading to:
• High context-switching overhead.
• Memory exhaustion (each thread consumes stack space).
• Potential JVM crashes or degraded performance.

Recommend that you use a thread pool (e.g., ExecutorService) instead of creating new threads in each iteration.

If you still want to report this as a bug, then the upstream OpenJDK project is the place to do so: https://mail.openjdk.org/mailman/listinfo/concurrency-discuss

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working Waiting on OP
Projects
None yet
Development

No branches or pull requests

2 participants