You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@jmeter.apache.org by "Draxler, Felix" <fe...@sap.com> on 2016/05/06 08:01:32 UTC

NegativeArraySizeException reading large test case

Hi all,



I want to load a very large test case (> 3GB) into JMeter. However, a NegativeArraySizeException is thrown inside a BufferedInputStream while reading the file.*

In this mail, I describe the cause of the error, have a guess why JMeter works this way and suggest a patch.



Why does this occur?

1) JMeter's SaveService#readTree wraps the InputStream it receives in a BufferedInputStream (BIS).

2) It then tells the BIS to save all read data in memory up to a size of Integer.MAX_VALUE by calling reader.mark(Integer.MAX_VALUE).

3) XStream successfully reads in bytes from the BIS. As requested in 2), the BIS saves all the bytes read into an array buffer.

4) As the file is large, the BIS at some point calculates a buffer size exceeding the integer range. This integer is mapped to a negative value (integer overflow).

5) BIS tries to allocate a byte buffer with this negative size, yielding the error.



In my understanding of SaveService#readTree, the BIS wrapping was introduced to fall back to the old Avalon format: In case loading the .jmx failed, the BIS was reset to the beginning of the file and the OldSaveService tried loading the file. So the buffer was needed because a FileInputStream normally doesn't support marking.



Reading the JMeter 3.0 Changelist, the *.jtl import is dropped. XStream does not depend on the InputStream being a BIS. So I guess it is safe to remove the BIS wrapping avoiding the above bug. See the patch below for my suggestion.**



How should I proceed? Report a bug in Bugzilla?



Thanks,

Felix Draxler







*Java 8 will instead throw a OutOfMemoryError "Required array size too large" for very similar reasons, but later in the execution. In this mail, I describe the situation with Java 7.



**Possible patch for SaveService.java:

-        if (!reader.markSupported()) {

-             reader = new BufferedInputStream(reader);

-         }

-        reader.mark(Integer.MAX_VALUE);