• 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。而且在内存中分配这么大的对象,在编码中也是不提倡的。

    I am chris, and what about you?
  • 相关阅读:
    python 数据结构--Set(集合)
    python 数据结构--Dictionary(字典)
    idea使用心得
    SpringBoot(一):构建第一个SpringBoot工程
    springboot服务的一些问题
    maven使用问题总结

    多线程学习三:Thread API,ThreadLocal,synchronized,volatile和Condition
    多线程学习二:线程池 ExecutorService
    多线程学习一:创建多线程的方式
  • 原文地址:https://www.cnblogs.com/arax/p/9163186.html
Copyright © 2020-2023  润新知