admin 管理员组

文章数量: 887042


2024年2月18日发(作者:宁波网络公司)

VM50内存溢出原因分析-20091118

1. 背景

VM50出现内存溢出,性能组对此问题进行了跟踪。

2. 前期分析

在内存溢出时抓取了Dump文件,查看heap信息,有一项不太正常。

793043b8 1047476 12569712 n

79307c84 535721 12857304 l

2f52dda8 42423 14084436 ster

2e14c210 74907 16479540 ute

79332178 1032867 16525872 64

查找一个ItemMaster对象的引用链

0:022> !gcroot a251b17c

Note: Roots found on stacks may be false positives. Run "!help gcroot" for

more info.

Scan Thread 12 OSTHread 14e0

ESP:202ed3c:Root:02b32290()->

aaeedbf4(ionContext)->

aaeedc18(calCallContext)->

aaeed894(ntext)->

aaeec144(orkerRequestInProcForIIS6)->

02b51d74(rkerRequest+EndOfSendNotification)->

02b51a48(ntime)->

02b51afc(tTimeoutManager)->

02b51b20([])->

02b51c18(LinkList)->

5197174c(tTimeoutManager+RequestTimeoutEntry)->

519711a4(ntext)->

06b30044()->

0ab6b8c0([][])->

0ab6b8d4([])->

51973d98(Dictionary)->

51973dac(ctionary)->

51973dc8(ctionary+DictionaryNode)->

51973ddc(ctionary+DictionaryNode)->

51973dfc(ctionary+DictionaryNode)->

51973df0(orStack)->

5197f5a8(List`1[[orContext, ]])->

5198fbe8(ListNode`1[[orContext, ]])->

5198fb50(orContext)->

5198fb60(Dictionary)->

5198fb74(ctionary)->

5198fb90(ctionary+DictionaryNode)->

5198fbb4(ctionary+DictionaryNode)->

5198fbd4(ctionary+DictionaryNode)->

5198fc00(ctionary+DictionaryNode)->

519901d8(ctionary+DictionaryNode)->

990089c4(ctionary+DictionaryNode)->

99003e88(ctCache)->

99003cf8()->

99003df8(venging)->

99003e30(List`1[[ationBasket, ]])->

a1e72e08(ListNode`1[[ationBasket, ]])->

aac8bf2c(ListNode`1[[ationBasket, ]])->

0de096e8(ListNode`1[[ationBasket, ]])->

97824258(ListNode`1[[ationBasket, ]])->

97822f68(ationBasket)->

97822f88([])->

97823fc4(ationBasket+EliminationItem)->

a25281fc(tem)->

a25281a0(`1[[stableObject,

]])->

a25281d4(tionGuardList)->

a251b3ec(Relation)->

a251b3a8(Value)->

a251b17c(ster)

被HttpContext引用住了,看一下该HttpContext中包含的Url信息。

0:022> !do 51973ee8

Name:

MethodTable: 793308ec

EEClass: 790ed64c

Size: 670(0x29e) bytes

(C:WINDOWSassemblyGAC_32mscorlib2.0.0.0__)

String:

vm50:80/Portal/ufsoft/?lnk=99f1b00a-1dc8-45e3-9331-2352aeeeac3e&chromeType=4&ShowType=ShowModal&ParentTaskID=e347e1a9-8503-42fb-8ada-aa5bce268399&EntityFullName=ster&CardFormID=053a1be3-2c56-428b-b221-b5291644f2cb&__sk=__SK61558&__curOId=1017&ShowAtlasModalDialog=true

程得恩协助确认了该功能点是料品列表的批量修改功能,并重现了该问题。

3. 分析过程

重现该问题后,收集到了该操作的调用栈。

。。。

1b47e05c 7fa25fc4 ()

1b47e070

()

1b47e214 2dc770cb e()

1b47e28c a63877fe ()

1b47e2ac a6386f6e

a6387e3e

(nDataContract, , , `1,

`1)

1b47e384 a6386d09

(xt,

`1 ByRef,

, , `1,

`1)

。。。(部分内容,完整见附件)

重点检查黄色部分的代码。

首先检查检查方法中的IDs

0:036> !do 0x0dfd4da4

Name: odifyBP

MethodTable: 55597298

EEClass: 555dcbd0

Size: 24(0x18) bytes

(D:portal-2009-11-18(v2.0))

Fields:

MT Field Offset Type VT Attr Value Name

793308ec 4000131 4 0 instance 0dfb7a1c

entityFullName

793308ec 4000132 8 0 instance 0dfd41bc oPath

00000000 4000133 c 0 instance 0dfd4164 entityIDs

00000000 4000134 10 0 instance 0dfd4dbc

modifyPropValues

0:036> !do 0dfd4164

Name: `1[[64, mscorlib]]

MethodTable: 793227ac

EEClass: 790e7478

Size: 24(0x18) bytes

(C:WINDOWSassemblyGAC_32mscorlib2.0.0.0__)

Fields:

MT Field Offset Type VT Attr Value Name

793320c8 40009d8 4 64[] 0 instance 0fb53f48 _items

79332b38 40009d9 c 32 1 instance 0 _size

79332b38 40009da 10 32 1 instance 0 _version

79330508 40009db 8 0 instance 00000000 _syncRoot

793320c8 40009dc 0 64[] 0 shared static

_emptyArray

Size是0,因此代码应该是走到了代码图的红色部分,继续检查list的值

0:024> !do 5199c82c

Name: `1[[stableObject,

]]

MethodTable: 2e141770

EEClass: 2e133b1c

Size: 28(0x1c) bytes

(C:meworkv2.0.50727Temporary

Filesportal863bec524df0d36assemblydl3efd6fb4ee89e06ba_)

Fields:

MT Field Offset Type VT Attr Value Name

7932a768 4000021 4 ... 0 instance 5199c848 innerList

00000000 4000022 8 0 instance 00000000 delLists

793308ec 4000023 c 0 instance 02b301d0

childAttrName

2303f0f8 4000024 10 ...PersistableObject 0 instance 00000000 parentPO

793308ec 4000025 14 0 instance 02b301d0

parentAttrName

0:024> !do 5199c848

Name: ist

MethodTable: 7933291c

EEClass: 790ee61c

Size: 24(0x18) bytes

(C:WINDOWSassemblyGAC_32mscorlib2.0.0.0__)

Fields:

MT Field Offset Type VT Attr Value Name

793040bc 40008fb 4 [] 0 instance 14ff0130 _items

79332b38 40008fc c 32 1 instance 42253 _size

79332b38 40008fd 10 32 1 instance 42253 _version

79330508 40008fe 8 0 instance 00000000 _syncRoot

793040bc 40008ff 1c4 [] 0 shared static emptyArray

Size是42253项,就是这个了,在中,将循环42253次调用方法,进行ItemMaster的Modify操作,由于最外层的list一直拿着ItemMaster的强引用,因此必须要等到全部ItemMaster都修改完成后,才能被释放。

4. 结论

对于FindAll返回对象过多,导致内存OOM的问题,一般要求开发转而使用DataReader解决。但是,从DataReader得到的是DB对象,在编程的方便性上远较BE对象为差。使用Page加载Entity对象的方式,内存占用可以保持在一个较小的水平,这非常好。但可惜的是获取下一页又要执行一次数据库查询,带领额外的数据库消耗。

因此,我们希望将Entity对象的便利和DataReader的高效结合起来,由平台支持EntityDataReader方式操纵数据。

针对本案例,由于只需要取Entity的ID属性,应该使用EntityDataQuery以Reader方式只获取Entity的ID属性。


本文标签: 对象 内存 方式 问题