我们知道.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]

开启LOH压缩?的更多相关文章

  1. Nginx 开启gzip 压缩

    随着nginx的发展,越来越多的网站使用nginx,因此nginx的优化变得越来越重要,今天我们来看看nginx的gzip压缩到底是怎么压缩的呢? gzip(GNU-ZIP)是一种压缩技术. 经过gz ...

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

    在用HttpWebRequest对象时,一般我们都没有开启gzip压缩,如果服务端返回的数据比较大,这是我们需要开启gzip压缩,怎么开启呢? 1.给HttpWebRequest对象,添加如下Head ...

  3. IIS7.5开启GZip压缩

    在IIS7.5选择要开启GZip压缩的网站,在功能视图中找到并双击"压缩"图标,在压缩界面中钩选"启用静态内容压缩"和"启用动态内容压缩", ...

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

    转自:http://down.chinaz.com/server/201202/1645_1.htm 最近无事研究一些Web的优化,用工具page speed检测网站时发现还没有开启gzip压缩,于是 ...

  5. IIS6.0开启gzip压缩(来自百度)

    IIS6.0开启gzip压缩 | 更新:2012-08-10 10:29 1 2 3 4 5 分步阅读 开启gzip可以极大的加速网站.有时压缩比率高达80%,近来测试了一下,最少都有40%以上,还是 ...

  6. apache 开启zgip 压缩模式

    一.Apache开启gzip压缩模式在目录apache\conf\httpd.conf 配置 httpd.conf 文件: #去掉LoadModule deflate_module modules/m ...

  7. Nginx开启gzip压缩功能

    在Nginx安装完成之后,我们可以开启Gzip压缩功能,这里Nginx默认只能对text/html类型的文件进行压缩.下面的指令为开启Gzip的指令: gzip on; gzip_http_versi ...

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

    在上一篇文章黑客流谈到了关于网页打开速度对SEO的影响,其中提到了网页开启Gzip压缩的好处,接下来我来和大家分享一下WINDOWS系统IIS服务器下如何开启Gzip压缩. 首先我们来了解一下什么是G ...

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

    1,设置文件静态缓存3天: 在httpd.conf 里添加如下代码: #文件静态缓存配置 <IfModule expires_module> #打开缓存 ExpiresActive on ...

随机推荐

  1. [TCPIP] IP路由表及选路 Note

    TCP/IP IP路由表及选路 1.路由表信息 路由表一般包含信息:目的IP地址.下一站路由器的IP地址.标志. 为数据报传送指定的一个网络接口. 查看路由表信息mac-abeen:~ abeen$ ...

  2. 个人项目制作(PSP)

    计划: 软件的此功能的实现,个人估算需要一个周的时间. 开发阶段: 需求分析: 1> 运动员希望软件可以记录自己的得分项. 2> 运动员希望软件可以记录自己的得分具体细节. 3>运动 ...

  3. angular的ng-repeat使用

    ng-repeat是angular的一个指令,用来循环生成某些东西.常用的是拿到数据循环生成样式展示在视图中. <!--orderStatuses表示$scope传递的数据$scope.orde ...

  4. 基于东北F4的设计模式情景剧——第一幕 装饰模式(Decorator Pattern)

    第一场 难题未解 布景:铁岭,晴天,午后,风.在一幢还算气派的写字楼的三层外墙上,挂着一条红色横幅,上面用歪歪扭扭的毛笔字写着"东北F4软件外包工作室".大风中,那早已褪色的条幅剧 ...

  5. 微信小程序-上传下载

    wx.uploadFile(OBJECT) 上传 将本地资源上传到开发者服务器.如页面通过 wx.chooseImage(图片)/wx.chooseVideo(视频) 等接口获取到一个本地资源的临时文 ...

  6. 字符串处理总结之二(C#StringBuilder类)

    动态串StringBuilder 与String类相比,System.Text.StringBuilder类可以实现动态字符串.此外,动态的含义是指在修改字符串时,系统不需要创建新的对象,不会重复开辟 ...

  7. DataTables 自定义

    自定义取的参数方法 getQueryCondition = function(data) { var param = {}; ]) { param.order =data.columns[data.o ...

  8. CodeUI Test:UIMap录制文件分析一

    UIMap文件是Coded UI Test的核心文件,它分为三个文件. 1.UIMap.uitest 这是xml文件,里面描述了所有需要操作的目标控件以及进行操作的动作等. 2.UIMap.Desig ...

  9. gulp 插件

    原文链接:http://www.mamicode.com/info-detail-517085.html gulp是什么? http://gulpjs.com/ 相信你会明白的! 与著名的构建工具gr ...

  10. HBase 数据读写流程

    HBase 数据读写流程 2016-10-18 杜亦舒 读数据 HBase的表是按行拆分为一个个 region 块儿,这些块儿被放置在各个 regionserver 中 假设现在想在用户表中获取 ro ...