开启LOH压缩?

我们知道.NET CLR的GC堆中有一种特殊的堆,它专门存放超过85000byte的对象(详见这里),这就是大对象堆(LOH)。

在.NET Framework 4.5.1之前,微软并没有提供对LOH的压缩操作,这是因为移动大对象的开销是很可观的。不能压缩LOH也会带来一些问题,比如LOH的内存碎片化。不过在.NET Framework 4.5.1种,微软加入了对LOH堆压缩的开关。对于为什么会加入这个开关,个人猜测应该是考虑到计算机性能足以支撑这种操作。具体使用参照以下代码:

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();    

对于GCLargeObjectHeapCompactionMode.CompactOnce的解释是,在下一次回收gen2时压缩LOH。也就是说这个设置每执行一次只起一次效果,这种设计是很合理的,毕竟如果作为永久开关则会造成不必要的压缩操作。虽然计算机性能足以支持LOH的压缩操作,但这并不意味着不会影响性能。

那么,我怎么知道这个操作达到了预期的效果呢?这就要上调试神器WinDbg了,虽然类似CLRProfiler也可以看出来,但就信息量来说WinDbg要胜一筹。

首先上测试代码:

class Program
{
    static void Main(string[] args)
    {
        //在LOH堆上放一个大对象,调用完后该对象即被认作是垃圾
        MakeALohObject();

        //在LOH堆上再放一个大对象,此时该对象会被保持
        var bytes = new byte[1024*1024];

        //注释和取消注释以下开关,并分别dump内存用于分析
        GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
        //触发all gc
        GC.Collect();

        Console.Read();
    }

    static void MakeALohObject()
    {
        var obj = new byte[1024 * 1024];
    }
}

下面是未打开压缩LOH开关的dump信息节选:

0:000> !eeheap
---------------省略部分信息
Number of GC Heaps: 1
generation 0 starts at 0x000001450b255b90
generation 1 starts at 0x000001450b251018
generation 2 starts at 0x000001450b251000
ephemeral segment allocation context: none
         segment             begin         allocated              size
000001450b250000  000001450b251000  000001450b255ba8  0x4ba8(19368)
Large object heap starts at 0x000001451b251000
         segment             begin         allocated              size
000001451b250000  000001451b251000  000001451b4599f0  0x2089f0(2132464)
Total Size:              Size: 0x20d598 (2151832) bytes.
------------------------------
GC Heap Size:            Size: 0x20d598 (2151832) bytes.

0:000> !dumpheap -stat
Statistics:
              MT    Count    TotalSize Class Name
----------------省略部分信息
00007ff8edfa2160        2          706 System.Char[]
00007ff8edfa61a8        2         1072 System.Globalization.CultureData
00007ff8edfa2360       17         1112 System.String[]
00007ff8edfa2f10       26         1456 System.RuntimeType
00007ff8edfa1010      154         6696 System.String
00007ff8edfa1688        5        35144 System.Object[]
00007ff8edfa7248        3      1048904 System.Byte[]
00000145095abf40       24      1051068      Free
Total 294 objects

0:000> !DumpHeap /d -mt 00000145095abf40
         Address               MT     Size
000001450b251000 00000145095abf40       24 Free
000001450b251018 00000145095abf40       24 Free
000001450b251030 00000145095abf40       24 Free
----------------省略部分信息
000001451b259980 00000145095abf40  1048662 Free

从!eeheap命令结果可以看出LOH共2132464byte,约2mb,也就是说虽然回收了一个1mb的byte数组,但是内存并未压缩。从!dumpheap -stat中的Free里面可以找到被释放的1mb空间。

接下来看看打开压缩LOH开关的内存dump:

0:000> !eeheap
----------------省略部分信息
Number of GC Heaps: 1
generation 0 starts at 0x0000015300005390
generation 1 starts at 0x0000015300001018
generation 2 starts at 0x0000015300001000
ephemeral segment allocation context: none
         segment             begin         allocated              size
0000015300000000  0000015300001000  00000153000053a8  0x43a8(17320)
Large object heap starts at 0x0000015310001000
         segment             begin         allocated              size
0000015310000000  0000015310001000  00000153101099b8  0x1089b8(1083832)
Total Size:              Size: 0x10cd60 (1101152) bytes.
------------------------------
GC Heap Size:            Size: 0x10cd60 (1101152) bytes.

0:000> !dumpheap -stat
Statistics:
              MT    Count    TotalSize Class Name
----------------省略部分信息
000001536ca7be30       16          414      Free
00007ff8edfa8520        1          432 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
00007ff8edfa39d8        6          524 System.Int32[]
00007ff8edfa2160        2          706 System.Char[]
00007ff8edfa61a8        2         1072 System.Globalization.CultureData
00007ff8edfa2360       17         1112 System.String[]
00007ff8edfa2f10       26         1456 System.RuntimeType
00007ff8edfa1010      154         6696 System.String
00007ff8edfa1688        5        35144 System.Object[]
00007ff8edfa7248        3      1048904 System.Byte[]
Total 286 objects

从上面可以看出LOH的size未1083832,即约1mb,这说明的确是将LOH压缩了,且!dumpheap -stat里的Free里也找不到这块空区域了。

说了这么多其实都不是重点,重点是既然我们用了LOH压缩,那么LOH压缩对性能会产生多大影响呢?首先我们要明白,启用LOH压缩并不是直接影响我们所编写的代码的执行性能,而是影响的GC回收性能。而GC回收的前奏就是挂起所有工作线程,所以GC每次执行的时间决定着整个系统将挂起多长时间。

那么接着贴一段代码,该段代码用于统计在启用和关闭LOH压缩的平均耗时:

class Program
{
    static void Main(string[] args)
    {
        var cycle = 1000;
        var total = 0l;
        //预热
        MakeGrabage();

        for (int j = 0; j < cycle; j++)
        {
            total += MakeGrabage();
        }
        Console.WriteLine("平均耗时{0}毫秒", total / (double)cycle);
        Console.Read();
    }

    static long MakeGrabage()
    {
        var objs = new byte[1000][];
        //初始化1000个1mb的byte数组
        for (int i = 0; i < 1000; i++)
        {
            objs[i] = new byte[1024 * 1024];
        }
        //将其中一半置为垃圾对象
        for (int i = 0; i < objs.Length; i++)
        {
            if (i % 2 == 0)
            {
                objs[i] = null;
            }
        }
        var sw = Stopwatch.StartNew();
        //开启或关闭LOH压缩
        GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
        GC.Collect();
        sw.Stop();
        var elasped = sw.ElapsedMilliseconds;

        objs = null;
        GC.Collect();
        return elasped;
    }
}

在上述条件下,我的机器跑出的结果是:不开启LOH压缩平均回收需要0.705毫秒,而开启后平均回收需要325.369毫秒,差了461倍。内存占用情况不开启LOH压缩平均在1400mb左右,开启后平均在850mb左右,内存是纯眼看,所以可能差距比较大。

就上述数据而言,LOH压缩还是在有必要的时候再用吧。

原创文章,转载请注明: 转载自xdlysk的博客

本文链接地址: 开启LOH压缩?[http://www.xdlysk.com/article/5826c1d2b16bc40409d5cac8]

时间: 2024-08-06 23:29:58

开启LOH压缩?的相关文章

php简单开启gzip压缩方法(zlib.output_compression)

网上的教程基本是你抄我来我抄他,不外乎加头加尾或者自构函数两种写法.实际上每个php页面都要去加代码——当然也可以include引用,不过总显得略微麻烦 一般而言,页面文件开启gzip压缩以后,其体积可以减小60%~90%,对于文字类站点,可以节省下大量的带宽与用户等待时间.但是不论是iis还是apache默认都只压缩html类静态文件,对于php文件需要模块配置才可支持(iis7.5中开启动态+静态压缩也可以),于是利用php自身功能到达gzip的效果也成为一项合理的诉求. 网上的教程基本是你

Tomcat7中开启gzip压缩功能的配置方法

使用gzip压缩可以减少数据传输大小,加快网页加载速度.很多大站都开启了gzip压缩,不过也有很多网站并没有开启gzip压缩,上次看了一篇文章说开启gzip压缩后对搜索引擎不友好,但从带宽和流量的角度来看,还是有必要开启gzip压缩的. 对于tomcat7服务器,打开conf文件夹下的server.xml 文件,找到 复制代码 代码如下: <Connector port="8080" protocol="HTTP/1.1" connectionTimeout=

WIN2003服务器IIS下如何开启GZIP压缩

在上一篇文章黑客流谈到了关于网页打开速度对SEO的影响,其中提到了网页开启Gzip压缩的好处,接下来我来和大家分享一下WINDOWS系统IIS服务器下如何开启Gzip压缩. 首先我们来了解一下什么是Gzip,Gzip是GNU zip的缩写,它是一个GNU自由软件的文件压缩程序,也经常用来表示gzip这种文件格式.gzip可以极大的加速网站,最高可以达到80%的压缩比率,利用Gzip的压缩算法来对服务器发布的网页内容进行压缩后再传输到客户端浏览器,这样实际上降低了网络传输的字节数,最明显的好处就是

修改Apache配置文件开启gzip压缩传输

转自:http://down.chinaz.com/server/201202/1645_1.htm 最近无事研究一些Web的优化,用工具page speed检测网站时发现还没有开启gzip压缩,于是上网找来资料实验一下:在apache2.0以上(包括apache2.0)的版中gzip压缩使用的是mod_deflate模块,下面是具体配置步骤 第1步 LoadModule deflate_module modules/mod_deflate.so LoadModule headers_modul

Apache开启Gzip压缩

1. 编辑Apache的httpd.conf文件 vim /etc/httpd/conf/httpd.conf 2. 开启mod_deflate.so模块 LoadModule deflate_module modules/mod_deflate.so 3. 对该模块进行配置 # GG到最下一行添加如下内容 <IfModule mod_deflate.c> # 压缩等级 9 DeflateCompressionLevel 9 # 压缩类型 html.xml.php.css.js SetOutp

apache 配置静态文件缓存和开启gzip压缩

1,设置文件静态缓存3天: 在httpd.conf 里添加如下代码: #文件静态缓存配置 <IfModule expires_module> #打开缓存 ExpiresActive on #文件缓存259200/3600/24=3天 ExpiresByType text/css A259200 ExpiresByType application/x-javascript A259200 ExpiresByType application/javascript A259200 ExpiresBy

【转载】HttpWebRequest开启gzip压缩简介

在用HttpWebRequest对象时,一般我们都没有开启gzip压缩,如果服务端返回的数据比较大,这是我们需要开启gzip压缩,怎么开启呢? 1.给HttpWebRequest对象,添加如下Header: request.Headers.Add("Accept-Encoding", "gzip"); 2.对接收到的流进行解码: private string GetResponseBody(HttpWebResponse response) { string res

Nginx开启gzip压缩功能

在Nginx安装完成之后,我们可以开启Gzip压缩功能,这里Nginx默认只能对text/html类型的文件进行压缩.下面的指令为开启Gzip的指令: gzip on; gzip_http_version 1.0; gzip_disable "MSIE [1-6]."; gzip_types text/plain application/x-javascript text/css text/javascript; 如果要能够是Nginx开启图片压缩功能,在配置文件中添加如下代码: gz

apache 开启zgip 压缩模式

一.Apache开启gzip压缩模式在目录apache\conf\httpd.conf 配置 httpd.conf 文件: #去掉LoadModule deflate_module modules/mod_deflate.soLoadModule headers_module modules/mod_headers.so #在文件的尾部添加一下代码:#配置需要压缩的文件格式:<ifmodule mod_deflate.c>SetOutputFilter DEFLATE#压缩级别,1-9,9为最