JVM中数组长度限制

发现问题

当写下这行代码时,程序会注定运行失败。

String strs[] = new String[Integer.MAX_VALUE];

错误信息:java.lang.OutOfMemoryError: Requested array size exceeds VM limit.

而且在jdk源码中总会看到类似这样的定义:

    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

分析问题

看注释可以了解到,jvm会为数组头信息保留一些空间。官方给出的解释。我们去看看jvm内部是如何实现的。

objArrayOop ArrayKlass::allocate_arrayArray(int n, int length, TRAPS) {
  //...
  if (length > arrayOopDesc::max_array_length(T_ARRAY)) {
    // 在这抛出异常
    report_java_out_of_memory("Requested array size exceeds VM limit");
    JvmtiExport::post_array_size_exhausted();
    THROW_OOP_0(Universe::out_of_memory_error_array_size());
  }
  //...
}

其中, T_ARRAY = 13,表示数据类型。

enum BasicType {
  T_BOOLEAN     =  4,
  T_CHAR        =  5,
  T_FLOAT       =  6,
  T_DOUBLE      =  7,
  T_BYTE        =  8,
  T_SHORT       =  9,
  T_INT         = 10,
  T_LONG        = 11,
  T_OBJECT      = 12,
  T_ARRAY       = 13,
  T_VOID        = 14,
  T_ADDRESS     = 15,
  T_NARROWOOP   = 16,
  T_METADATA    = 17,
  T_NARROWKLASS = 18,
  T_CONFLICT    = 19, // for stack value type with conflicting contents
  T_ILLEGAL     = 99
};

根据数据类型,获得对象头大小

    // 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_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_down(max_jint - header_size(type), MinObjAlignment);
        }
        return (int32_t)max_elements_per_size_t;
    }

至此我们了解到,jvm中,数组对象的头上是有一些信息的,这些信息需要占用一定的空间,所以在java中,新建数组是不可以指定其大小为Integer.MAX_VALUE。而且在内存中分配这么大的对象,在编码中也是不提倡的。

posted @ 2018-06-10 14:14  arax  阅读(573)  评论(0编辑  收藏  举报