Mismatch between JDK and JVM re largest byte array that VM can allocate?

Srinivas Ramakrishna ysr1729 at gmail.com
Mon Mar 11 16:11:10 PDT 2013


I am looking at code in (for example) ByteArrayOutputStream.java :-

       96     /**

       97      * Increases the capacity to ensure that it can hold at least the

       98      * number of elements specified by the minimum capacity argument.

       99      *

      100      * @param minCapacity the desired minimum capacity

      101      */

      102     private void grow(int minCapacity) {

      103         // overflow-conscious code

      104         int oldCapacity = buf.length;

      105         int newCapacity = oldCapacity << 1;

      106         if (newCapacity - minCapacity < 0)

      107             newCapacity = minCapacity;

      108         if (newCapacity < 0) {

      109             if (minCapacity < 0) // overflow

      110                 throw new OutOfMemoryError();

      111             newCapacity = Integer.MAX_VALUE;

      112         }

      113         buf = Arrays.copyOf(buf, newCapacity);

      114     }


This can result in a request for an array of size Integer.MAX_VALUE
(because of line 111 above), see below:-

     2874     /**

     2875      * Copies the specified array, truncating or padding
with zeros (if necessary)

     2876      * so the copy has the specified length.  For all indices that are

     2877      * valid in both the original array and the copy, the
two arrays will

     2878      * contain identical values.  For any indices that are
valid in the

     2879      * copy but not the original, the copy will contain
<tt>(byte)0</tt>.

     2880      * Such indices will exist if and only if the specified length

     2881      * is greater than that of the original array.

     2882      *

     2883      * @param original the array to be copied

     2884      * @param newLength the length of the copy to be returned

     2885      * @return a copy of the original array, truncated or
padded with zeros

     2886      *     to obtain the specified length

     2887      * @throws NegativeArraySizeException if
<tt>newLength</tt> is negative

     2888      * @throws NullPointerException if <tt>original</tt> is null

     2889      * @since 1.6

     2890      */

     2891     public static byte[] copyOf(byte[] original, int newLength) {

     2892         byte[] copy = new byte[newLength];

     2893         System.arraycopy(original, 0, copy, 0,

     2894                          Math.min(original.length, newLength));

     2895         return copy;

     2896     }


So the call at line 2892 can cause a request for an array with
Integer.MAX_VALUE entries, yet the JVM doesn't give you arrays that
large; witness this code in arrayOop.cpp where this will flatten out:-

  // Return the maximum length of an array of BasicType.  The length can passed
  // to typeArrayOop::object_size(scale, length, header_size) without causing an
  // overflow. We also need to make sure that this will not overflow a size_t on
  // 32 bit platforms when we convert it to a byte size.
  static int32_t max_array_length(BasicType type) {
    assert(type >= 0 && type < T_CONFLICT, "wrong type");
    assert(type2aelembytes(type) != 0, "wrong type");

    const size_t max_element_words_per_size_t =
      align_size_down((SIZE_MAX/HeapWordSize - header_size(type)),
MinObjAlignment);
    const size_t max_elements_per_size_t =
      HeapWordSize * max_element_words_per_size_t / type2aelembytes(type);
    if ((size_t)max_jint < max_elements_per_size_t) {
      // It should be ok to return max_jint here, but parts of the code
      // (CollectedHeap, Klass::oop_oop_iterate(), and more) uses an int for
      // passing around the size (in words) of an object. So, we need to avoid
      // overflowing an int when we add the header. See CRs 4718400 and 7110613.
      return align_size_down(max_jint - header_size(type), MinObjAlignment);
    }
    return (int32_t)max_elements_per_size_t;
  }


Is there any plan to fix this mismatch ? May be it's as simple(!) as
checking the GC code to make sure it doesn't traffic in int's and
fix the code above to return max_jint for the byte array case as well?
I have a vague recollection of a bug id already for this, but
it's been a while....

Thanks!
-- ramki


More information about the hotspot-gc-dev mailing list