zoukankan      html  css  js  c++  java
  • 关于GC进行垃圾回收的时机

    前言


    今天查看一个同事的代码,发现代码中多处地方使用了GC.Collect()方法,我问他为什么这么做,他说感觉程序中定义了好多变量,怕GC回收不及时,用GC.Collect()可以手动掌控GC进行垃圾回收。

    先不说他对GC的垃圾回收机制还不了解,就是调用GC.Collect()后GC真的会不会回收这个问题都需要再深入了解一下。

    GC.Collect


    下面我们通过一个小例子,来看一下使用GC.Collect后的内存情况。

    我们知道可以通过GCHandle设置引用类型(可直接复制到本机结构中的类型)在GC垃圾回收时不移动地址,并且获取地址值,那么就可以通过在两次地址获取中间加入Collect方法,来判断GC是否真的进行了垃圾回收。

    using System;
    using System.Runtime.InteropServices;
    
    namespace TestGCCollect
    {
        class Program
        {
            static void Main(string[] args)
            {
                //创建一个没有引用的垃圾对象
                new object();
                //这是我们要判定地址的对象
                int[] gcTest = new int[10];
                
                //设定Pinned通知GC在进行回收的时候不移动地址
                GCHandle gcHandle1 = GCHandle.Alloc(gcTest, GCHandleType.Pinned);
                //获取gcTest在堆中的地址并输出
                IntPtr add1 = gcHandle1.AddrOfPinnedObject();
                Console.WriteLine(add1.ToString());
                //通知GC当程序返回的时候可以回收
                gcHandle1.Free();
                
                //调用GC回收object垃圾
                GC.Collect();
                
                //再次获取地址
                GCHandle gcHandle2 = GCHandle.Alloc(gcTest, GCHandleType.Pinned);
                IntPtr add2 = gcHandle2.AddrOfPinnedObject();
                Console.WriteLine(add2.ToString());
                gcHandle2.Free();
                
                Console.ReadKey();
            }
        }
    }

    我们发现地址并没有变化!

    修改一下代码使用for循环生成多个object:

                //创建没有引用的垃圾对象
                for (int i = 0; i < 30000; i++)
                    new object();
                //这是我们要判定地址的对象
                int[] gcTest = new int[10];

    重新编译后,执行结果如下:

    地址变了!

    通过上面的代码,我们知道GC.Collect并不是只要执行就会进行垃圾回收,实际上GC会首先判断当前是不是真的需要进行回收,如果内存中只有很小的垃圾(碎片化不严重)时,这时候启动回收显然得不偿失,影响性能。

    总结


    1. 永远都不要手动进行GC.Collect操作。如果你认为有,需要检查你地代码

    2. 即使当你手动进行垃圾回收时,GC还不会立即执行,它要先判断是否真正需要回收

  • 相关阅读:
    androidstudio配置模拟器路径
    Linux常见命令
    逆向助手使用
    Git服务器回滚到固定版本
    Git使用
    使用本地Gradle版本
    系统模拟器创建
    AndroidStudio设置代理
    关联、参数化、思考时间、检查点、事务的设置方式
    SQL:内连接、左外连接、右外连接、全连接、交叉连接区别
  • 原文地址:https://www.cnblogs.com/houkui/p/4234461.html
Copyright © 2011-2022 走看看