Basic chapter: object object

Time:2021-3-2

1 object memory structure and pointer compression to understand

Basic chapter: object object

//Hotspot's oop.hpp Class oopdesc in file
class oopDesc {
  friend class VMStructs;
  private:
  volatile markOop  _ Mark; // object header
  union _ Metadata {// klassoop class metadata pointer
    Klass*      _klass;   
    narrowKlass _compressed_klass;
  } _metadata;
  • Object instance data memory consists of three parts,Object headerActual data areaMemory alignment area
  • The layout of the object header is as follows: it is mainly related to the lock, hashcode and garbage collection; because the content of the lock mechanism is too long, I won’t explain it here; the memory layout of markword (markoop) related to the lock is as follows

Basic chapter: object object

  • memory alignment The automatic memory management system of hotspot VM requires that the starting address of the object must be an integer multiple of 8 bytes, in other words, the size of the object must be an integer multiple of 8 bytes. Therefore, when the data part of the object instance is not aligned, it needs to be filled by alignment.
  • memory alignment benefit

    • It is good for memory management
    • Faster CPU reading: CPU gets data from memory, not one byte by one, but according to the length that CPU can process. For example, 32-bit computer is a 4-byte memory block; when only two bytes are needed, the memory processor will process and select. If three bytes need to be distributed in two different memory blocks (four byte memory block), the memory needs to be read twice (if the same memory block exists, only one reading is required). When the objects are reasonably aligned according to certain rules, the CPU can request the least memory and speed up the execution speed of the CPU
  • Pointer compression

    • As can be seen from the figure above, in 64 bit JVM, the mark word of object is twice as large as that of 32-bit. In fact, klassoop is doubled, accounting for 64 bits (the length of array is fixed four bytes). The width of the pointer increases, but for the heap memory less than 4G, it seems that the 64 bit pointer can not be used. Can this be optimized? The answer is pointer compression
    • The principle of pointer compression is to encode and decode by implanting compression instructions into JVM
    • What information will be compressed

      • Object to be compressed: class property, object header information, object reference type, object array type
      • Uncompressed objects: local variables, stack elements, input parameters, return values, null pointers
    • When pointer compression is enabled, the size of klassoop can be changed from 64bit to 32bit. For the size of objects, see the following specific comparison: JVM – analyze the pointer compression of Java object header object header
    public static void main(String[] args){
        Object a = new object(); // 16b to turn off compression or 16b, 8b multiple is required; 12b + 4B filled
        Int [] arr = New Int [10]; // 24B when compression is off, it is 16b
    }
    
    public class ObjectNum {
        //8B mark word
        //4b Klass pointer if compression is off, 8b is occupied
        //-20: - usecompansedclasspointers or - XX: - usecompansedoops,
        int id;        //4B
        String name; // 4B if compression is turned off, 8b is occupied
        Byte B; // 1b actual memory may be filled to 4B
        Object o; // 4B if compression is turned off, 8b is occupied
    }
    • Why is it better that the heap memory should not exceed 32g and the pointer should use 32 bits when pointer compression is turned on? Why is the maximum available memory 32g instead of 4G
< br / > the JVM requires that the starting position of the object be aligned at a multiple of 8 bytes, which can be used to improve the location range to '2 ^ 11 * 4G' in theory. However, the JVM only moves the pointer three bits to the left, so '2 ^ 3 * 4G = 32g'. If * * is greater than 32g * *, pointer compression will fail. If the GC heap size is less than * * 4G * *, the high 32 bits will be cut directly to avoid the encoding and decoding process
-Enable pointer compression '- XX: + usecompressedoops' (* * on by default * *), disable pointer compression:' - XX: - usecompressedoops'`

Several basic methods of 2 object

  • Local method

    • private static native void registerNatives()Link the local method defined by object with Java program. Registernatives in object class
    • public final native Class<?> getClass()Get the class metadata of Java
    • public native int hashCode()Gets the hash code of the object
    • protected native Object clone() throws CloneNotSupportedExceptionGet the clone object of the object, shallow copy
    • public final native void notify()Wake up a thread in the waiting object lock waitset queue
    • public final native void notifyAll()Similar to notify (), wakes up all threads in the waiting object lock waitset queue
    • public final native void wait(long timeout)Release the object lock and enter the waitset queue of the object lock
  • Common method

    public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode());}
    public boolean equals(Object obj) { return (this == obj);}
    public final void wait(long timeout, int nanos) throws InterruptedException;
    //They are all based on native void wait (long timeout)
    public final void wait() throws InterruptedException;
    wait(long timeout, int nanos)、wait() 
    //This method is specifically called before the JVM recycles the object 
    protected void finalize() throws Throwable;

3 == 、 equals、 Comparable.compareTo 、 Comparator.compara Four comparison methods

If you do not specify the sort order, the default sort order in Java is ascending, from small to large

  • ==(a) the comparison between basic types is value (b) the comparison between basic types and encapsulated types is value (c) the comparison between reference types is memory address
  • Equals (object o), which can be seen in the object basic methodpublic boolean equals(Object obj) { return (this == obj);}We use = = to compare. The advantage of the equals method is that we can override it
  • Comparable.compareTo Is an abstract method in the interface comparable; if the object implements the interface, you can use the Collections.sort (list < T > Col). Next, let’s see how the source code is implemented

    Collections.java
    // Collections.sort (list < T > list), calling the sort method of list
    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
    }

    The sort of list calls the Arrays.sort

    List.java
    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }

    Call if comparator C is null Arrays.sort (object [] a); finally, the legacymergesort method is called for processing

    Arrays.java
    public static <T> void sort(T[] a, Comparator<? super T> c) {
        if (c == null) {
            sort(a);
        } else {
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, c);
            else
                TimSort.sort(a, 0, a.length, c, null, 0, 0);
        }
    }

    A piece of code in the legacymergesort method; the final bottom layer is to use theMerge sortAnd CompareTo

    Arrays.java
    ......
        if (length < INSERTIONSORT_THRESHOLD) {
            for (int i=low; i<high; i++)
                for (int j=i; j>low &&
                         ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                    swap(dest, j, j-1);
            return;
        }
  • Comparator is also an interface, but it provides richer operations and needs to be implementedint compare(T o1, T o2)method
    < br / > comparator provides several common static methods such as then comparing, reversed, and reverseorder (the operation object needs to implement comparator or comparable) List.sort 、 Stream.sorted 、 Collections.sort use.

    @Data
    @AllArgsConstructor
    static class Pair implements Comparator<Pair>, Comparable<Pair> {
        Integer one;
        Integer two;
        @Override
        public String toString() { return one + "-" + two; }
        @Override
        public int compareTo(Pair o) { return one.compareTo(o.one);  }
        @Override
        public int compare(Pair o1, Pair o2) {return o1.compareTo(o2);}
    }
    public static void main(String[] args) {
        List<Pair> col = Arrays.asList( new Pair(4, 6), new Pair(4, 2),new Pair(1, 3));
        col.sort(Comparator.reverseOrder());
        System.out.println("----------------");
        col.stream().sorted(Comparator.comparing(Pair::getOne).thenComparing(Pair::getTwo))
                .forEach(item ->  System.out.println(item.toString()) );
    }

    Collections.sort By default, it is sorted in ascending order. You can see that reverse order reverses the order. For col with then comparing, it first determines the size of pair:: getone. If it is equal, it determines the size of pair:: gettwo to sort

    result:
    4-6
    4-2
    1-3
    ----------------
    1-3
    4-2
    4-6

4 method rewriting and overloading

  • MethodologicalrewriteThe definition of a subclass and the method of a superclassThe name, parameters and sequence are consistentNote that subclasses override methodsModifier It can’t be more strict, that is to say, the modifier of the parent class method is protected, and the subclass can’t be modified by private, but can be thrown by publicabnormalIt can’t be defined more broadly than the parent method
  • Methodologicalheavy loadIs defined in the same class and the existing methodThe name is consistent but the parameter or parameter order is inconsistentThe return value cannot determine the overload of the method
  • Overloaded methods can be determined at compile time (compile time polymorphism), while overridden methods need to be determined at run time (runtime polymorphism, which we often call polymorphism)
    < br / > three necessary conditions for polymorphism: 1. Inheritance; 2. Subclass overriding parent class method; 3. Parent class reference pointing to child class object

Whether the construction method can be overridden

The construction method is unique to each class and cannot be inherited by the subclass. Because the construction method has no return value, the subclass cannot define the same method as the construction method of the parent class. However, in the same class, construction methods can be overloaded

public class TestEquals {
    int i;
    public TestEquals() {   i = 0; }
    //Construction method overload
    public TestEquals(int i) {   this.i = i } 
}

6. Equals and hashcode of object

Equals is used to compare whether two objects are equal. You can override this method to implement a custom comparison method, while hashcode is used to obtain the hash value of an object, or override this method. When the object is stored in the map, it is the first to use the Object.hashCode Judge whether the mapping is in the same position. If it is in the same mapping bit, use equals to compare whether the two objects are the same.

What’s wrong with 7 equals and hashcode?

If rewriting equals results in the same objects but different hashcodes, it is against the JDK specification; moreover, when using HashMap to store, there may be multiple objects that we think are the same, which will lay a hole for our code logic.

eight Object.wait and Thread.sheep

Object.wait It needs to be used in the synchronized decorated code, which will give up the CPU and give up the holding state of the object lock. and Thread.sleep Then simply suspend and give up CPU without releasing any lock resources

9 use of finalize method

  • If the object overrides the finalize method, the JVM registers the current object in the ReferenceQueue queue of the finalizerthread. Object has no other strong reference. When garbage collection, the JVM will judge that the ReferenceQueue has the object, and will not recycle it temporarily. After that, finalizerthread (independent of the garbage collection thread) fetches the object from the ReferenceQueue, executes the custom finalize method, and then removes the object from the queue for the next garbage collection
  • Finalization may cause object to be recycled later, which may lead to memory overflow. Use it with caution
  • The difference between finally and finally

    • Finally is a Java keyword used to handle exceptions. It is used with try
    • If return occurs before finally, will the finally code block be executed? < br / > continue, break and return in try cannot bypass the execution of finally code block. Finally will be executed after try
  • Similar keyword final

    • Final modify class, which cannot be inherited; modify method, which cannot be rewritten; modify variable, which cannot point to new value; modify array, which cannot point to new array, but array element can be changed
    • If the object is modified by final, how many ways can variables be declared and assigned?
    • Fianl modifies common variables: 1. Declaration at definition time 2. Declaration of code block within class 3. Constructor declaration
    • Fianl modifies static variables: 1. Declaration at definition time; 2. Static code block declaration within class

What are the ways to create objects

  • 1. Create with new
  • 2. Use reflection to get class, in newinstance ()
  • 3. Call the clone () method of the object
  • 4. It is obtained by deserialization, such as:ObjectInputStream.readObject()

11 guess the number of objects created

  • String one = new String("Hello");

<br/> Two objectsAnd oneStack variables: a stack variable one, a new string() instance object, and a “hello” string object

Basic chapter: object object

  • Digression: string.intern (); intern first determines whether the constant pool contains the same string, and returns the reference if it exists; otherwise, the reference of the string first appears in the record heap in the constant pool and returns the reference.

< br / > if it is executed firstString s = "hello" ;It is equivalent to executing Intern (); first create “hello” in the constant pool, save reference a into the constant pool, and return it to s. In this case, string (“hello”). Intern() will return the reference a of the constant pool

String one = "hello";
    String two = new String("hello");
    String three = one.intern();
    System.out.println(two == one);
    System.out.println(three == one);
    
    result:
    False // one is not equal to two, but their char [] value points to the same block of memory
    True // one and three references are the same

Basic chapter: object object

12 object copy problem

  • Reference objectAssignment copyIs a copied reference object,A a = new A(); A b = a; At this point, a and B point to the same block of memory
  • use Object.clone () method. If the field is of value type (basic type), the value is copied. If the field is of reference type, the reference of the object is copied instead of the object

    @Getter
    static class A implements Cloneable{
        private B b; 
        private int index;
        public A(){
            b = new B(); index = 1000;
        }
        public A clone()throws CloneNotSupportedException{  return (A)super.clone(); }
    }
    static class B{
    }
    public static void main(String[] args) throws Exception{
        A a = new A();
        A copyA = a.clone();
        System.out.println( a.getIndex() == copyA.getIndex() );
        System.out.println( a.getB() == copyA.getB() );
    }
    //All returned results are true. The reference type only copies the reference value
    true
    true
  • Deep copy: use serial copy when rewriting clone method. (note that Cloneable and serializable need to be implemented)

    public A clone() throws CloneNotSupportedException {
            try {
                ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
                ObjectOutputStream out = new ObjectOutputStream(byteOut);
                out.writeObject(this);
                ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
                ObjectInputStream inputStream = new ObjectInputStream(byteIn);
                return (A) inputStream.readObject();
            } catch (Exception e) {
                e.printStackTrace();
                throw new CloneNotSupportedException(e.getLocalizedMessage());
            }
        }

Pay attention to the official account, and we will exchange with you.

Basic chapter: object object

Reference article

  • Registernatives in object class
  • Why not use finalize in Java
  • How much memory does a Java object occupy?
  • The size of Java object in memory
  • Why memory alignment is needed and a simple analysis of alignment rules
  • JVM analysis of pointer compression of object header in Java
  • A few pictures are easy to understand String.intern ()