加入收藏 | 设为首页 | 会员中心 | 我要投稿 源码网 (https://www.900php.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 资源网站 > 空间 > 正文

.Net 垃圾回收和大对象处理

发布时间:2016-07-26 00:12:09 所属栏目:空间 来源:伯乐在线
导读:CLR垃圾回收器根据所占空间大小划分对象。大对象和小对象的处理方式有很大区别。比如内存碎片整理 —— 在内存中移动大对象的成本是昂贵的,让我们研究一下垃圾回收器是如

让我们先看下分配大对象的代价。 CLR为每个新对象分配内存时都要保证这些内存清空的,是没有被其他对象使用的(I give out is cleared)。这就意味着分配的代价完全被清理(clearing)的代价控制着(除非在分配时触发了一次垃圾回收)。如果清空1byte需要2个周期(cycles),就意味着清除一个最小的大对象需要170,000个周期。通常情况下人们不会分配超大的对象,比如说在2GHz的机器上分配16M大小的对象,大约需要16ms来清空内存。这代价太大了。

让我们在看下回收的代价。前面提到过,大对象和2代龄对象一起回收。如果大对象或者2代对象占用空间超过其阀值时,就会触发2代对象的回收。如果2代回收因为大对象堆超过阀值被触发,2代对象堆本身没有多少对象可以做回收。如果在2代堆上没有多少对象,这问题不大。但是如果2代堆很大对象很多,过多的2代回收就会导致性能问题。如果是临时性的分配大对象,就需要很多的时间来运行垃圾回收;也就是说如果你持续的使用大对象然后又释放大对象对性能会有很大的负面影响。

大对象堆上的巨大对象通常是数组(很少有一个对象很大的情况)。如果对象中的元素是强引用,代价会很高;如果元素之间没有相互引用,垃圾回收时就不需要遍历整个数组。例如:用一个数组来保存二叉树的节点,一种方法是在节点中强引用左右节点:

class Node

{

Data d;

Node left;

Node right;

}

Node[] binaryTree = new Node[num_nodes];

如果num_nodes是一个很大的数字,就意味着每个节点都至少需要查看二个引用元素。一种替代方案是在节点中保存左右节点元素的数组索引号

class Node

{

Data d;

uint left_index;

uint right_index;

}

这样的话,元素之间的引用关系去掉了;可以通过binaryTree[left_index]来获得引用的节点。垃圾回收器在做垃圾回收时也不需要看相关的引用元素了。

为大对象堆收集性能数据

有几种方法可以收集大对象堆相关的性能数据。在我解释这些方法之前,让我们先谈一下为什么需要收集大对象堆相关的性能数据。

在你开始上搜集某个方面的性能数据时,有可能你已经找到这方面造成性能瓶颈的证据;或者你已经没有找遍了所有方面都没有发现问题。

在查找性能问题时.Net CLR Memory 性能计数器通常是应该先考虑使用的工具。和LOH相关的计数器有generation 2 collectioins(2代堆收集次数)和large object heap size大对象堆大小。Generation 2 collections显示的是进程启动之后2代垃圾回收操作发生的次数。Large object heap size计数器显示的是当前大对象堆的大小值,包括空闲空间;这个计数器是在每次垃圾回收操作之后做更新,并非每次分配内存都做更新。

可以参考下图在windows性能计数器中观察.Net CLR Memory相关性能数据

.Net 垃圾回收和大对象处理

你也可以通过程序查询这些计数器的值;很多人通过程序的方式收集性能计数器来帮助查找性能瓶颈。

当然也可以使用调试器winddbg观察大对象堆。

最后提示一下:到目前为止,大对象堆作为垃圾回收的一部分是不做内存碎片整理的,但是这个只是一个clr的实现细节,程序代码不应该依赖这个特点。如果要确保对象不会被垃圾回收器移动,就要使用fixed语句。

文章来源:伯乐在线

(编辑:源码网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读