对象实例在JVM中的布局

  1. 在java语言层面的一个对象实例对应一个JVM中的instanceOopDesc
    参考/openjdk/hotspot/src/share/vm/oops/instanceOopDesc.hpp文件可知:
// An instanceOop is an instance of a Java Class
// Evaluating "new HashTable()" will create an instanceOop.
class instanceOopDesc : public oopDesc {
    // 此处省略好多内容
}
  1. 参考/openjdk/hotspot/src/share/vm/oops/oop.hpp文件可知:
    • 对象头markOop,参考/openjdk/hotspot/src/share/vm/oops/markOop.hpp文件:

      // The markOop describes the header of an object.
      //
      // Note that the mark is not a real oop but just a word.
      // It is placed in the oop hierarchy for historical reasons.
      //
      // Bit-format of an object header (most significant first, big endian layout below):
      //
      //  32 bits:
      //  --------
      //             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
      //             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
      //             size:32 ------------------------------------------>| (CMS free block)
      //             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
      //
      //  64 bits:
      //  --------
      //  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
      //  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
      //  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
      //  size:64 ----------------------------------------------------->| (CMS free block)
      //
      //  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)
      //  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)
      //  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
      //  unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
      //
      //  - hash contains the identity hash value: largest value is
      //    31 bits, see os::random().  Also, 64-bit vm's require
      //    a hash value no bigger than 32 bits because they will not
      //    properly generate a mask larger than that: see library_call.cpp
      //    and c1_CodePatterns_sparc.cpp.
      //
      //  - the biased lock pattern is used to bias a lock toward a given
      //    thread. When this pattern is set in the low three bits, the lock
      //    is either biased toward a given thread or "anonymously" biased,
      //    indicating that it is possible for it to be biased. When the
      //    lock is biased toward a given thread, locking and unlocking can
      //    be performed by that thread without using atomic operations.
      //    When a lock's bias is revoked, it reverts back to the normal
      //    locking scheme described below.
      //
      //    Note that we are overloading the meaning of the "unlocked" state
      //    of the header. Because we steal a bit from the age we can
      //    guarantee that the bias pattern will never be seen for a truly
      //    unlocked object.
      //
      //    Note also that the biased state contains the age bits normally
      //    contained in the object header. Large increases in scavenge
      //    times were seen when these bits were absent and an arbitrary age
      //    assigned to all biased objects, because they tended to consume a
      //    significant fraction of the eden semispaces and were not
      //    promoted promptly, causing an increase in the amount of copying
      //    performed. The runtime system aligns all JavaThread* pointers to
      //    a very large value (currently 128 bytes (32bVM) or 256 bytes (64bVM))
      //    to make room for the age bits & the epoch bits (used in support of
      //    biased locking), and for the CMS "freeness" bit in the 64bVM (+COOPs).
      //
      //    [JavaThread* | epoch | age | 1 | 01]       lock is biased toward given thread
      //    [0           | epoch | age | 1 | 01]       lock is anonymously biased
      //
      //  - the two lock bits are used to describe three states: locked/unlocked and monitor.
      //
      //    [ptr             | 00]  locked             ptr points to real header on stack
      //    [header      | 0 | 01]  unlocked           regular object header
      //    [ptr             | 10]  monitor            inflated lock (header is wapped out)
      //    [ptr             | 11]  marked             used by markSweep to mark an object
      //                                               not valid at any other time
      //
      //    We assume that stack/thread pointers have the lowest two bits cleared.
      
      class markOopDesc: public oopDesc {
      public:
        // Constants
        enum { age_bits                 = 4,
               lock_bits                = 2,
               biased_lock_bits         = 1,
               max_hash_bits            = BitsPerWord - age_bits - lock_bits - biased_lock_bits,
               hash_bits                = max_hash_bits > 31 ? 31 : max_hash_bits,
               cms_bits                 = LP64_ONLY(1) NOT_LP64(0),
               epoch_bits               = 2
        };
      
        // The biased locking code currently requires that the age bits be
        // contiguous to the lock bits.
        enum { lock_shift               = 0,
               biased_lock_shift        = lock_bits,
               age_shift                = lock_bits + biased_lock_bits,
               cms_shift                = age_shift + age_bits,
               hash_shift               = cms_shift + cms_bits,
               epoch_shift              = hash_shift
        };
      
        enum { lock_mask                = right_n_bits(lock_bits),
               lock_mask_in_place       = lock_mask << lock_shift,
               biased_lock_mask         = right_n_bits(lock_bits + biased_lock_bits),
               biased_lock_mask_in_place= biased_lock_mask << lock_shift,
               biased_lock_bit_in_place = 1 << biased_lock_shift,
               age_mask                 = right_n_bits(age_bits),
               age_mask_in_place        = age_mask << age_shift,
               epoch_mask               = right_n_bits(epoch_bits),
               epoch_mask_in_place      = epoch_mask << epoch_shift,
               cms_mask                 = right_n_bits(cms_bits),
               cms_mask_in_place        = cms_mask << cms_shift
      #ifndef _WIN64
               ,hash_mask               = right_n_bits(hash_bits),
               hash_mask_in_place       = (address_word)hash_mask << hash_shift
      #endif
        };
      
        // Alignment of JavaThread pointers encoded in object header required by biased locking
        enum { biased_lock_alignment    = 2 << (epoch_shift + epoch_bits)
        };
      
      #ifdef _WIN64
          // These values are too big for Win64
          const static uintptr_t hash_mask = right_n_bits(hash_bits);
          const static uintptr_t hash_mask_in_place  =
                                  (address_word)hash_mask << hash_shift;
      #endif
      
        enum { locked_value             = 0,
               unlocked_value           = 1,
               monitor_value            = 2,
               marked_value             = 3,
               biased_lock_pattern      = 5
        };
      
        enum { no_hash                  = 0 };  // no hash value assigned
      
        enum { no_hash_in_place         = (address_word)no_hash << hash_shift,
               no_lock_in_place         = unlocked_value
        };
      
        enum { max_age                  = age_mask };
      
        enum { max_bias_epoch           = epoch_mask };
      
      }
      

    • 元数据_metadata,参考/openjdk/hotspot/src/share/vm/oops/kclass.hpp/openjdk/hotspot/src/share/vm/oops/instanceKlass.hpp ,比如

       // An InstanceKlass is the VM level representation of a Java class.
      // It contains all information needed for at class at execution runtime.
      
      //  InstanceKlass layout:
      //    [C++ vtbl pointer           ] Klass
      //    [subtype cache              ] Klass
      //    [instance size              ] Klass
      //    [java mirror                ] Klass
      //    [super                      ] Klass
      //    [access_flags               ] Klass
      //    [name                       ] Klass
      //    [first subklass             ] Klass
      //    [next sibling               ] Klass
      //    [array klasses              ]
      //    [methods                    ]
      //    [local interfaces           ]
      //    [transitive interfaces      ]
      //    [fields                     ]
      //    [constants                  ]
      //    [class loader               ]
      //    [source file name           ]
      //    [inner classes              ]
      //    [static field size          ]
      //    [nonstatic field size       ]
      //    [static oop fields size     ]
      //    [nonstatic oop maps size    ]
      //    [has finalize method        ]
      //    [deoptimization mark bit    ]
      //    [initialization state       ]
      //    [initializing thread        ]
      //    [Java vtable length         ]
      //    [oop map cache (stack maps) ]
      //    [EMBEDDED Java vtable             ] size in words = vtable_len
      //    [EMBEDDED nonstatic oop-map blocks] size in words = nonstatic_oop_map_size
      //      The embedded nonstatic oop-map blocks are short pairs (offset, length)
      //      indicating where oops are located in instances of this klass.
      //    [EMBEDDED implementor of the interface] only exist for interface
      //    [EMBEDDED host klass        ] only exist for an anonymous class (JSR 292 enabled)
      
       class InstanceKlass: public Klass {
        protected:
        // Annotations for this class
        Annotations*    _annotations;
        // Array classes holding elements of this class.
        Klass*          _array_klasses;
        // Constant pool for this class.
        ConstantPool* _constants;
        // The InnerClasses attribute and EnclosingMethod attribute. The
        // _inner_classes is an array of shorts. If the class has InnerClasses
        // attribute, then the _inner_classes array begins with 4-tuples of shorts
        // [inner_class_info_index, outer_class_info_index,
        // inner_name_index, inner_class_access_flags] for the InnerClasses
        // attribute. If the EnclosingMethod attribute exists, it occupies the
        // last two shorts [class_index, method_index] of the array. If only
        // the InnerClasses attribute exists, the _inner_classes array length is
        // number_of_inner_classes * 4. If the class has both InnerClasses
        // and EnclosingMethod attributes the _inner_classes array length is
        // number_of_inner_classes * 4 + enclosing_method_attribute_size.
        Array<jushort>* _inner_classes;
      
        // the source debug extension for this klass, NULL if not specified.
        // Specified as UTF-8 string without terminating zero byte in the classfile,
        // it is stored in the instanceklass as a NULL-terminated UTF-8 string
        char*           _source_debug_extension;
        // Array name derived from this class which needs unreferencing
        // if this class is unloaded.
        Symbol*         _array_name;
      
        // Number of heapOopSize words used by non-static fields in this klass
        // (including inherited fields but after header_size()).
        int             _nonstatic_field_size;
        int             _static_field_size;    // number words used by static fields (oop and non-oop) in this klass
        // Constant pool index to the utf8 entry of the Generic signature,
        // or 0 if none.
        u2              _generic_signature_index;
        // Constant pool index to the utf8 entry for the name of source file
        // containing this klass, 0 if not specified.
        u2              _source_file_name_index;
        u2              _static_oop_field_count;// number of static oop fields in this klass
        u2              _java_fields_count;    // The number of declared Java fields
        int             _nonstatic_oop_map_size;// size in words of nonstatic oop map blocks
      
        // _is_marked_dependent can be set concurrently, thus cannot be part of the
        // _misc_flags.
        bool            _is_marked_dependent;  // used for marking during flushing and deoptimization
      
        enum {
          _misc_rewritten            = 1 << 0, // methods rewritten.
          _misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops
          _misc_should_verify_class  = 1 << 2, // allow caching of preverification
          _misc_is_anonymous         = 1 << 3, // has embedded _host_klass field
          _misc_is_contended         = 1 << 4, // marked with contended annotation
          _misc_has_default_methods  = 1 << 5  // class/superclass/implemented interfaces has default methods
        };
        u2              _misc_flags;
        u2              _minor_version;        // minor version number of class file
        u2              _major_version;        // major version number of class file
        Thread*         _init_thread;          // Pointer to current thread doing initialization (to handle recusive initialization)
        int             _vtable_len;           // length of Java vtable (in words)
        int             _itable_len;           // length of Java itable (in words)
        OopMapCache*    volatile _oop_map_cache;   // OopMapCache for all methods in the klass (allocated lazily)
        MemberNameTable* _member_names;        // Member names
        JNIid*          _jni_ids;              // First JNI identifier for static fields in this class
        jmethodID*      _methods_jmethod_ids;  // jmethodIDs corresponding to method_idnum, or NULL if none
        nmethodBucket*  _dependencies;         // list of dependent nmethods
        nmethod*        _osr_nmethods_head;    // Head of list of on-stack replacement nmethods for this class
        BreakpointInfo* _breakpoints;          // bpt lists, managed by Method*
        // Array of interesting part(s) of the previous version(s) of this
        // InstanceKlass. See PreviousVersionWalker below.
        GrowableArray<PreviousVersionNode *>* _previous_versions;
        // JVMTI fields can be moved to their own structure - see 6315920
        // JVMTI: cached class file, before retransformable agent modified it in CFLH
        JvmtiCachedClassFileData* _cached_class_file;
      
        volatile u2     _idnum_allocated_count;         // JNI/JVMTI: increments with the addition of methods, old ids don't change
      
        // Class states are defined as ClassState (see above).
        // Place the _init_state here to utilize the unused 2-byte after
        // _idnum_allocated_count.
        u1              _init_state;                    // state of class
        u1              _reference_type;                // reference type
      
        JvmtiCachedClassFieldMap* _jvmti_cached_class_field_map;  // JVMTI: used during heap iteration
      
        NOT_PRODUCT(int _verify_count;)  // to avoid redundant verifies
      
        // Method array.
        Array<Method*>* _methods;
        // Default Method Array, concrete methods inherited from interfaces
        Array<Method*>* _default_methods;
        // Interface (Klass*s) this class declares locally to implement.
        Array<Klass*>* _local_interfaces;
        // Interface (Klass*s) this class implements transitively.
        Array<Klass*>* _transitive_interfaces;
        // Int array containing the original order of method in the class file (for JVMTI).
        Array<int>*     _method_ordering;
        // Int array containing the vtable_indices for default_methods
        // offset matches _default_methods offset
        Array<int>*     _default_vtable_indices;
      
        // Instance and static variable information, starts with 6-tuples of shorts
        // [access, name index, sig index, initval index, low_offset, high_offset]
        // for all fields, followed by the generic signature data at the end of
        // the array. Only fields with generic signature attributes have the generic
        // signature data set in the array. The fields array looks like following:
        //
        // f1: [access, name index, sig index, initial value index, low_offset, high_offset]
        // f2: [access, name index, sig index, initial value index, low_offset, high_offset]
        //      ...
        // fn: [access, name index, sig index, initial value index, low_offset, high_offset]
        //     [generic signature index]
        //     [generic signature index]
        //     ...
        Array<u2>*      _fields;
      
        // embedded Java vtable follows here
        // embedded Java itables follows here
        // embedded static fields follows here
        // embedded nonstatic oop-map blocks follows here
        // embedded implementor of this interface follows here
        //   The embedded implementor only exists if the current klass is an
        //   iterface. The possible values of the implementor fall into following
        //   three cases:
        //     NULL: no implementor.
        //     A Klass* that's not itself: one implementor.
        //     Itsef: more than one implementors.
        // embedded host klass follows here
        //   The embedded host klass only exists in an anonymous class for
        //   dynamic language support (JSR 292 enabled). The host class grants
        //   its access privileges to this class also. The host class is either
        //   named, or a previously loaded anonymous class. A non-anonymous class
        //   or an anonymous class loaded through normal classloading does not
        //   have this embedded field.
        //
       }
      

      //
      // A Klass provides:
      //  1: language level class object (method dictionary etc.)
      //  2: provide vm dispatch behavior for the object
      // Both functions are combined into one C++ class.
      
      // One reason for the oop/klass dichotomy in the implementation is
      // that we don't want a C++ vtbl pointer in every object.  Thus,
      // normal oops don't have any virtual functions.  Instead, they
      // forward all "virtual" functions to their klass, which does have
      // a vtbl and does the C++ dispatch depending on the object's
      // actual type.  (See oop.inline.hpp for some of the forwarding code.)
      // ALL FUNCTIONS IMPLEMENTING THIS DISPATCH ARE PREFIXED WITH "oop_"!
      
      //  Klass layout:
      //    [C++ vtbl ptr  ] (contained in Metadata)
      //    [layout_helper ]
      //    [super_check_offset   ] for fast subtype checks
      //    [name          ]
      //    [secondary_super_cache] for fast subtype checks
      //    [secondary_supers     ] array of 2ndary supertypes
      //    [primary_supers 0]
      //    [primary_supers 1]
      //    [primary_supers 2]
      //    ...
      //    [primary_supers 7]
      //    [java_mirror   ]
      //    [super         ]
      //    [subklass      ] first subclass
      //    [next_sibling  ] link to chain additional subklasses
      //    [next_link     ]
      //    [class_loader_data]
      //    [modifier_flags]
      //    [access_flags  ]
      //    [last_biased_lock_bulk_revocation_time] (64 bits)
      //    [prototype_header]
      //    [biased_lock_revocation_count]
      //    [_modified_oops]
      //    [_accumulated_modified_oops]
      //    [trace_id]
      class Klass : public Metadata {
      protected:
        // note: put frequently-used fields together at start of klass structure
        // for better cache behavior (may not make much of a difference but sure won't hurt)
        enum { _primary_super_limit = 8 };
      
        // The "layout helper" is a combined descriptor of object layout.
        // For klasses which are neither instance nor array, the value is zero.
        //
        // For instances, layout helper is a positive number, the instance size.
        // This size is already passed through align_object_size and scaled to bytes.
        // The low order bit is set if instances of this class cannot be
        // allocated using the fastpath.
        //
        // For arrays, layout helper is a negative number, containing four
        // distinct bytes, as follows:
        //    MSB:[tag, hsz, ebt, log2(esz)]:LSB
        // where:
        //    tag is 0x80 if the elements are oops, 0xC0 if non-oops
        //    hsz is array header size in bytes (i.e., offset of first element)
        //    ebt is the BasicType of the elements
        //    esz is the element size in bytes
        // This packed word is arranged so as to be quickly unpacked by the
        // various fast paths that use the various subfields.
        //
        // The esz bits can be used directly by a SLL instruction, without masking.
        //
        // Note that the array-kind tag looks like 0x00 for instance klasses,
        // since their length in bytes is always less than 24Mb.
        //
        // Final note:  This comes first, immediately after C++ vtable,
        // because it is frequently queried.
        jint        _layout_helper;
      
        // The fields _super_check_offset, _secondary_super_cache, _secondary_supers
        // and _primary_supers all help make fast subtype checks.  See big discussion
        // in doc/server_compiler/checktype.txt
        //
        // Where to look to observe a supertype (it is &_secondary_super_cache for
        // secondary supers, else is &_primary_supers[depth()].
        juint       _super_check_offset;
      
        // Class name.  Instance classes: java/lang/String, etc.  Array classes: [I,
        // [Ljava/lang/String;, etc.  Set to zero for all other kinds of classes.
        Symbol*     _name;
      
        // Cache of last observed secondary supertype
        Klass*      _secondary_super_cache;
        // Array of all secondary supertypes
        Array<Klass*>* _secondary_supers;
        // Ordered list of all primary supertypes
        Klass*      _primary_supers[_primary_super_limit];
        // java/lang/Class instance mirroring this class
        oop       _java_mirror;
        // Superclass
        Klass*      _super;
        // First subclass (NULL if none); _subklass->next_sibling() is next one
        Klass*      _subklass;
        // Sibling link (or NULL); links all subklasses of a klass
        Klass*      _next_sibling;
      
        // All klasses loaded by a class loader are chained through these links
        Klass*      _next_link;
      
        // The VM's representation of the ClassLoader used to load this class.
        // Provide access the corresponding instance java.lang.ClassLoader.
        ClassLoaderData* _class_loader_data;
      
        jint        _modifier_flags;  // Processed access flags, for use by Class.getModifiers.
        AccessFlags _access_flags;    // Access flags. The class/interface distinction is stored here.
      
        // Biased locking implementation and statistics
        // (the 64-bit chunk goes first, to avoid some fragmentation)
        jlong    _last_biased_lock_bulk_revocation_time;
        markOop  _prototype_header;   // Used when biased locking is both enabled and disabled for this type
        jint     _biased_lock_revocation_count;
      
        TRACE_DEFINE_KLASS_TRACE_ID;
      
        // Remembered sets support for the oops in the klasses.
        jbyte _modified_oops;             // Card Table Equivalent (YC/CMS support)
        jbyte _accumulated_modified_oops; // Mod Union Equivalent (CMS support)
      
       }
      

    • 实例数据

// oopDesc is the top baseclass for objects classes.  The {name}Desc classes describe
// the format of Java objects so the fields can be accessed from C++.
// oopDesc is abstract.
// (see oopHierarchy for complete oop class hierarchy)
//
// no virtual functions allowed
class oopDesc {
 private:
  volatile markOop  _mark;
  union _metadata {
    Klass*      _klass;
    narrowKlass _compressed_klass;
  } _metadata;
  
  private:
  // field addresses in oop
  void*     field_base(int offset)        const;

  jbyte*    byte_field_addr(int offset)   const;
  jchar*    char_field_addr(int offset)   const;
  jboolean* bool_field_addr(int offset)   const;
  jint*     int_field_addr(int offset)    const;
  jshort*   short_field_addr(int offset)  const;
  jlong*    long_field_addr(int offset)   const;
  jfloat*   float_field_addr(int offset)  const;
  jdouble*  double_field_addr(int offset) const;
  Metadata** metadata_field_addr(int offset) const;

}

总算把对象的内存布局搞清楚了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容

  • 本来是要查找企业宣传页制作软件的,却意外发现了这款软件,浏览了一下,还真心不错,决定常用之,特此留文,以致纪念!意...
    Erin随便说阅读 220评论 0 0
  • I've just been a penny on the train track my entire life ...
    肩上的香樟树阅读 221评论 0 0
  • linux shell 可以用户定义函数,然后在shell脚本中可以随便调用。 格式: 说明: 可以带functi...
    AsaGuo阅读 281评论 0 0