zoukankan      html  css  js  c++  java
  • 安全点和安全区域

    前面介绍了垃圾回收器几个方面的内容:

    • 如何标记垃圾
    • 如何处理垃圾

    那么还有什么问题要解决呢?

    既然是自动垃圾回收,那么自动是什么情况呢?

    在我看来,自动主要来自两个方面:

    • 当我们年轻代、老年代内存不足时,触发某种条件,进行垃圾收集
    • 还有一个就是我们接下来说的安全点、安全区域

    安全点

    为什么要有安全点呢?

    在一个程序执行过程中,我们不一定要等到内存不足的时候,再进行垃圾回收整理。

    如果只是等待到内存不足的时候再进行整理,那么这个时候,就会有大量的垃圾,那么处理起来,要耗费的时间就会增长。

    所以,为了减少这种行为,平时的时候就可以进行收集。可以看下下面这个程序。

    package GC;
    
    import java.util.ArrayList;
    
    public class SafePoint {
        public static void main(String[] args) {
            while(true){
                ArrayList<Integer> list = new ArrayList<>();
                for (int i = 0; i < 1000; i++) {
                    list.add(i);
                }
            }
        }
    }
    

    这个程序,每次一个新的循环的时候,之前的list引用就指向了新的引用。我们设置 JVM 运行参数为:

    -XX:+PrintGCDetails -Xms10m -Xmx10m

    设置打印 GC 收集的过程,以及堆的大小为 10M。

    可以看到,垃圾回收器并没有等到内存不足的时候再去清理。而是在 2M 左右的时候,就去进行了清理。再清理之后,内存占用只有 1M 不到。

    像这种,在程序的某个点进行垃圾回收的,这个点就是安全点。

    在垃圾回收的过程中,如果程序仍在运行,有可能使得对象的引用发生改变,那么也许我们上一秒标记的存活对象,这一秒就是死亡对象了。

    所以,我们相对而言,要寻找那种,让程序运行比较耗时的指令出,进行安全点的设置。进而允许垃圾回收,比如方法调用,循环跳转,异常跳转等。

    安全点与垃圾回收

    注意:程序运行到安全点,不是一定要进行垃圾回收。而是在这些点上进行垃圾回收,较为安全。所以叫做安全点。

    如何在垃圾收集发生时,让所有线程到达最近的安全点?

    • 抢先式中断:发生垃圾回收时,所有的线程都中断,如果有的线程不在安全点,那么恢复一会,再中断,直到到达安全点
    • 主动式中断:如果有线程到达安全点,会去主动询问一个标识位,这个标志位说明,要不要发生中断。如果需要发生中断,那么这个线程就会中断自己,等到垃圾回收。

    抢先式中断,会造成大量的线程切换,浪费大量的时间,所以几乎不使用。更多的是使用 主动式中断。

    安全区域

    我们上面说了,线程运行时的状态,寻找安全点进行询问是否垃圾回收。

    那么如果线程处于 睡眠 或者 阻塞 状态,那么怎么办?这个时候,他就无法进行询问标志位了。

    如果在线程进入这些状态前,标示自己可以随时被 垃圾回收器 进行相关对象的标记即可。

    其实,这就是安全区域,因为一旦线程进入这些状态,那么其内对象不会发生改变,所以也就是随时可以被垃圾回收器进行处理。

    如果当线程重新启动后,发生垃圾回收器还没处理完,那么就继续等待。如果垃圾回收器没有处理或者已经处理完了,那么就继续执行。

    安全区域,无非就是另一个告诉垃圾回收器,你可以处理我的方式。

    package GC;
    
    public class SafeRegion {
        public static void main(String[] args) throws InterruptedException {
            byte[] bigSize = new byte[10 * 1024 * 1024];
            bigSize = null;
            new Thread(()->{
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.gc();
            }).start();
            Thread.sleep(10000);
        }
    }
    

    可以看到,主线程已经进入睡眠状态,这个时候,再另一个线程中,调用垃圾回收,仍然可以对垃圾进行清理。

  • 相关阅读:
    正则匹配 sql语句参数
    正则判断是不是移动端浏览
    .net 2.0 后台多线程
    Oracle 获取当天数据
    C# 图片转Base64
    Js FileReader图片加载
    KendoUI操作笔记
    Android Studio解析Json文件内容
    LitePal
    C#最基本的小说爬虫
  • 原文地址:https://www.cnblogs.com/zhouzhiyao/p/13172612.html
Copyright © 2011-2022 走看看