Comprensión en profundidad de la captura de pantalla de la máquina virtual Java curso-5-Sr. Song Hongkang

[ Del video de la estación B: https://www.bilibili.com/video/BV1BJ41177cp?p=154 ]

[Cita fuerte, débil, débil: es una pregunta de entrevista de alta frecuencia más parcial. Oye.

[Resultados de la prueba: solo muestran que cuando se llama al método System.gc (), se encuentra que el método finaliize anulado por la clase SystemGCTes a veces se llama y a veces no se llama, lo que muestra que el método System.gc () tiene tal descargo de responsabilidad: No hay garantía de que se llame al recolector de basura.

//测试不同情况下的GC。结果很妙,可以亲自测试下。-XX:PrintGCDetails
public class LocalVarGC {
    public void localvarGC1() {
        byte[] buffer = new byte[10 * 1024 * 1024];//10MB
        System.gc();
    }
    public void localvarGC2() {
        byte[] buffer = new byte[10 * 1024 * 1024];
        buffer = null;
        System.gc();
    }
    public void localvarGC3() {
        {
            byte[] buffer = new byte[10 * 1024 * 1024];
        }
        System.gc();
    }
    public void localvarGC4() {
        {
            byte[] buffer = new byte[10 * 1024 * 1024];
        }
        int value = 10;
        System.gc();
    }
    public void localvarGC5() {
        localvarGC1();
        System.gc();
    }
    public static void main(String[] args) {
        LocalVarGC local = new LocalVarGC();
        local.localvarGC5();//这里改变为不同的方法调用
    }
}

 

[Con el desarrollo iterativo de GC, en circunstancias normales, a menos que la memoria ocupada por la aplicación crezca muy rápido, haciendo que la recolección de basura se mantenga al día con la velocidad del consumo de memoria, OOM no es fácil de producir. El escenario para informar OOM es: desea asignar memoria para un nuevo objeto, pero la JVM no tiene suficiente memoria libre y, después de la recolección de basura, no puede proporcionar suficiente memoria libre. En este momento, se informará un error OOM.

[Qué tipo de división de espacio de memoria, como montón, pila, área de método, etc., es la división de memoria del nivel de la máquina virtual Java, que se llama memoria virtual . Sabes, todas nuestras aplicaciones se ejecutan en la máquina virtual Java.

[Pregunta de la entrevista: Casos de pérdida de memoria: (1) Modo singleton (2) Algunos recursos que proporcionan cierre no están cerrados, lo que provoca pérdidas de recursos]

[ ¿Qué es una fuga de memoria? Una fuga de memoria significa que algunos objetos java ya no se usan en la aplicación, pero porque algunas otras referencias java aún en uso en la aplicación aún mantienen una relación de referencia con ellos, es decir, estas Aunque los objetos java ya no se utilizan, todavía hay una cadena de referencia de GCRoots a ellos, lo que hace que el recolector de basura no pueda reclamarlos, lo que conduce a una pérdida de memoria. ¿Puede dar ejemplos de pérdidas de memoria? (1) En el algoritmo de recuento de referencias, el caso de referencias circulares es un ejemplo de fugas de memoria. Sin embargo, en Java, los algoritmos de recuento de referencias no se utilizan para identificar objetos basura, pero se utilizan algoritmos de análisis de accesibilidad para identificar objetos alcanzables. Por tanto, el ejemplo de referencia circular mencionado anteriormente debe tener una premisa, es decir, bajo la premisa del algoritmo de recuento de referencias. (2) En el contexto del algoritmo de análisis de accesibilidad, los ejemplos de pérdidas de memoria son: (2.1) Por ejemplo, en el modo singleton, el ciclo de vida del singleton es tan largo como la aplicación, por lo que en el singleton, si sostiene un objeto externo Si se hace referencia a él, este objeto externo no se puede reciclar y se producirá una pérdida de memoria. (2.2) Por ejemplo, algunos recursos que proporcionan el método close () no se cierran a tiempo y causan pérdidas de memoria , como conexiones de E / S, conexiones de bases de datos, etc. Estos recursos deben liberarse a tiempo después de que se agoten, de lo contrario causarán pérdidas de memoria. .

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

//用来感受下STW事件的存在!
public class StopTheWorldDemo {
    public static class WorkThread extends Thread {
        List<byte[]> list = new ArrayList<byte[]>();
        public void run() {
            try {
                while (true) {
                    for(int i = 0;i < 1000;i++){
                        byte[] buffer = new byte[1024];
                        list.add(buffer);
                    }
                    if(list.size() > 10000){
                        list.clear();
                        System.gc(); //会触发full gc,进而会出现STW事件
                    }
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    public static class PrintThread extends Thread {
        public final long startTime = System.currentTimeMillis();
        public void run() {
            try {
                while (true) {
                    // 每秒打印时间信息
                    long t = System.currentTimeMillis() - startTime;
                    System.out.println(t / 1000 + "." + t % 1000);
                    Thread.sleep(1000);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        WorkThread w = new WorkThread();
        PrintThread p = new PrintThread();
        w.start(); //两种测试场景:(1)注释掉测试。(2)不注释掉测试。
        p.start();
    }
}

    

[Subproceso de recolección de basura y subproceso de usuario: no en ningún momento, el subproceso del usuario puede detenerse y dejar que el subproceso de recolección de basura recolecte basura. Solo en ciertas ubicaciones el subproceso del usuario puede detenerse temporalmente y dejar que el subproceso de recolección de basura vaya a GC. Estas ubicaciones específicas son "puntos seguros" . Ejemplo: Por ejemplo, cuando se conduce por una autopista, no se puede parar en ningún punto de la autopista a voluntad, solo en las áreas de servicio se permite detenerse y descansar, estas áreas de servicio son similares a la existencia de puntos de seguridad .

[Pregunta de la entrevista: ¿Cómo comprobar que todos los subprocesos se han detenido en el punto seguro más cercano cuando ocurre la GC?

  

[Nota: Las cuatro referencias fuertes, débiles y débiles mencionadas en este capítulo  se explican todas cuando el objeto es accesible. Si el objeto es inalcanzable, se reciclará directamente.

[Nota: Las cuatro referencias fuertes, débiles y débiles mencionadas en este capítulo  se explican todas cuando el objeto es accesible. Si el objeto es inalcanzable, se reciclará directamente.

[Primera recolección de basura: se refiere al proceso de reciclaje de objetos Java intocables (u objetos Java inalcanzables). OOM no tiene nada que ver con "referencias no sólidas" , porque cuando se trata de OOM, se reciclarán las "referencias no sólidas", y yo he sido reciclado, y la JVM todavía aparece OOM, entonces esta OOM tiene una relación conmigo.

import java.lang.ref.SoftReference;
//软引用的测试:内存不足即回收。-Xms10m -Xmx10m -XX:+PrintGCDetails
public class SoftReferenceTest {
    public static class User {
        public User(int id, String name) {
            this.id = id;
            this.name = name;
        }
        public int id;
        public String name;
        @Override
        public String toString() {
            return "[id=" + id + ", name=" + name + "] ";
        }
    }

    public static void main(String[] args) {
        //创建对象,建立软引用
//        SoftReference<User> userSoftRef = new SoftReference<User>(new User(1, "songhk"));
        //上面的一行代码,等价于如下的三行代码
        User u1 = new User(1,"songhk");
        SoftReference<User> userSoftRef = new SoftReference<User>(u1);
        u1 = null;//一定要有的代码:取消强引用

        //从软引用中重新获得强引用对象
        System.out.println(userSoftRef.get());

        System.gc();
        System.out.println("After GC:");
//        //垃圾回收之后获得软引用中的对象
        System.out.println(userSoftRef.get());//由于堆空间内存足够,所有不会回收软引用的可达对象。
//
        try {
            //让系统认为内存资源紧张、不够
//            byte[] b = new byte[1024 * 1024 * 7];//让系统认为内存资源不够
            byte[] b = new byte[1024 * 7168 - 635 * 1024];//让系统认为内存资源紧张
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            //再次从软引用中获取数据
            System.out.println(userSoftRef.get());//在报OOM之前,垃圾回收器会回收软引用的可达对象。
        }
    }
}

[Nota: Las cuatro referencias fuertes, débiles y débiles mencionadas en este capítulo  se explican todas cuando el objeto es accesible. Si el objeto es inalcanzable, se reciclará directamente.

import java.lang.ref.WeakReference;
//弱引用的测试:发现即回收
public class WeakReferenceTest {
    public static class User {
        public User(int id, String name) {
            this.id = id;
            this.name = name;
        }
        public int id;
        public String name;
        @Override
        public String toString() {
            return "[id=" + id + ", name=" + name + "] ";
        }
    }

    public static void main(String[] args) {
        //构造了弱引用
        WeakReference<User> userWeakRef = new WeakReference<User>(new User(1, "songhk"));
        //从弱引用中重新获取对象
        System.out.println(userWeakRef.get());

        System.gc();
        // 不管当前内存空间足够与否,都会回收它的内存
        System.out.println("After GC:");
        //重新尝试从弱引用中获取对象
        System.out.println(userWeakRef.get());
    }
}

[Nota: Las cuatro referencias fuertes, débiles y débiles mencionadas en este capítulo  se explican todas cuando el objeto es accesible. Si el objeto es inalcanzable, se reciclará directamente.

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
//虚引用的测试:对垃圾回收没有任何影响。
//给对象设置一个虚引用关联关系的唯一目的:就是在对象垃圾回收器回收之时收到一个系统通知。
public class PhantomReferenceTest {
    public static PhantomReferenceTest obj;//声明一个当前类的对象obj
    static ReferenceQueue<PhantomReferenceTest> phantomQueue = null;//引用队列
    public static class CheckRefQueue extends Thread {
        @Override
        public void run() {
            while (true) {
                if (phantomQueue != null) {
                    PhantomReference<PhantomReferenceTest> objt = null;
                    try {
                        objt = (PhantomReference<PhantomReferenceTest>) phantomQueue.remove();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (objt != null) {
                        System.out.println("追踪垃圾回收过程:PhantomReferenceTest实例被GC了");
                    }
                }
            }
        }
    }

    @Override
    protected void finalize() throws Throwable { //finalize()方法只能被调用一次!
        super.finalize();
        System.out.println("调用当前类的finalize()方法");
        obj = this; //使当前对象复活
    }

    public static void main(String[] args) {
        Thread t = new CheckRefQueue();
        t.setDaemon(true);//设置为守护线程:当程序中没有非守护线程时,守护线程也就执行结束。
        t.start();

        phantomQueue = new ReferenceQueue<PhantomReferenceTest>();
        obj = new PhantomReferenceTest(); //obj是个强引用
        //构造了 PhantomReferenceTest 对象的虚引用,并指定了引用队列
        //使得obj这个强引用关联一个虚引用phantomRef
        PhantomReference<PhantomReferenceTest> phantomRef = new PhantomReference<PhantomReferenceTest>(obj, phantomQueue);

        try {
            //不可获取虚引用中的对象:返回null
            System.out.println(phantomRef.get());

            obj = null;//将强引用去除
            //第一次进行GC,由于obj这个强引用对象在finalize()方法中复活了,所以GC无法回收它
            System.gc(); //第一次GC
            Thread.sleep(1000); //由于GC线程优先级较低,这句话是为了让GC线程执行一下
            if (obj == null) {
                System.out.println("obj 是 null");
            } else {
                System.out.println("obj 可用");
            }

            System.out.println("第 2 次 gc");
            obj = null;//将强引用去除
            System.gc(); //第二次GC,一旦将obj对象回收,就会将此虚引用存放到引用队列中
            Thread.sleep(1000);
            if (obj == null) {
                System.out.println("obj 是 null");
            } else {
                System.out.println("obj 可用");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

 

 

 

 

 

 

Supongo que te gusta

Origin blog.csdn.net/cmm0401/article/details/108908310
Recomendado
Clasificación