dlink设置-android sqlite
![framework 4 0 64位](/uploads/image/0358.jpg)
2023年4月6日发(作者:蚂蚁森林出现金色能量球)
浅析c#内存泄漏
⼀直以来都对内存泄露和内存溢出理解的不是很深刻。在⽹上看到了⼏篇⽂章,于是整理了⼀下⾃⼰对内存泄露和内存溢出的理解。
⼀.概念
内存溢出:指程序在运⾏的过程中,程序对内存的需求超过了超过了计算机分配给程序的内存,从⽽造成“Outofmemory”之类的错
误,使程序不能正常运⾏。
造成内存溢出有⼏种情况:1.计算机本⾝的内存⼩,当同时运⾏多个软件时,计算机得内存不够⽤从⽽造成内存溢出。对于这种情况,只能
增加计算机内存来解决。2.软件程序的问题,程序在运⾏时没能及时释放不⽤的内存,造成使⽤的内存越来越⼤从⽽造成内存溢出。对于这
种情况,可以修改程序的代码来解决。
内存泄露:内存泄漏指由于疏忽或错误造成程序不能释放或不能及时释放已经不再使⽤的内存的情况,是应⽤程序分配某段内存后,由于设
计错误,失去了对该段内存的控制,因⽽造成了内存不能回收和不能及时回收。当程序不能释放的内存越来越多是就会造成程序的性能下降
或出现内存溢出的错误。
⼆、内存泄露检测⼯具:
oryProfiler-找到内存泄漏并优化内存使⽤针对C#,,或其它.Net程序。
&JavaProfiler-业界领先的Java和.NET程序性能分析⼯具。
tedQAAQTime-AutomatedQA的获奖产品performanceprofiling和memorydebugging⼯具集的下⼀代替换产品,⽀持
Microsoft,Borland,Intel,Compaq和GNU编译器。可以为.NET和Windows程序⽣成全⾯细致的报告,从⽽帮助您轻松隔离并排除代码
中含有的性能问题和内存/资源泄露问题。⽀持.Net1.0,1.1,2.0,3.0和Windows32/64位应⽤程序。
riptMemoryLeakDetector-微软全球产品开发欧洲团队(GlobalProductDevelopment-Europeteam,GPDE)发布的⼀
款调试⼯具,⽤来探测JavaScript代码中的内存泄漏,运⾏为IE系列的⼀个插件。
7.在单元测试时,在代码中检测,如.net下使⽤ine("Totalmemory:{0:###,###,###,##0}bytes",
alMemory(true));代码可以查看当前使⽤的内存。
⼆、导致内存泄露的常见情况及解决⽅法:
1.未退订的事件
是否没有⼿动注销事件就会造成内存泄露,我们先看这个问题
[csharp]
estClassHasEvent
2.{
delegatevoidTestEventHandler(objectsender,EventArgse);
eventTestEventHandlerYourEvent;
tedvoidOnYourEvent(EventArgse)
6.{
(YourEvent!=null)YourEvent(this,e);
8.}
9.}
10.
estListener
12.{
[]m_ExtraMemory=newbyte[1000000];
14.
eTestClassHasEvent_inject;
16.
TestListener(TestClassHasEventinject)
18.{
19._inject=inject;
20._ent+=entHandler(_inject_YourEvent);
21.}
22.
_inject_YourEvent(objectsender,EventArgse)
24.{
25.
26.}
27.}
28.
rogram
30.{
voidDisplayMemory()
32.{
ine("Totalmemory:{0:###,###,###,##0}bytes",alMemory(true));
34.}
35.
voidMain()
37.{
yMemory();
ine();
(inti=0;i<5;i++)
41.{
ine("---NewListener#{0}---",i+1);
43.
tener=newTestListener(newTestClassHasEvent());
er=null;//可有可⽆
46.
t();
rPendingFinalizers();
t();
yMemory();
51.
52.}
();
54.}
55.}
运⾏结果:
我们来改⼀⾏代码:
把下⾯这段:
1classTestClassHasEvent
2{
3publicdelegatevoidTestEventHandler(objectsender,EventArgse);
4publiceventTestEventHandlerYourEvent;
5protectedvoidOnYourEvent(EventArgse)
6{
7if(YourEvent!=null)YourEvent(this,e);
8}
9}
10
11classTestListener
12{
13byte[]m_ExtraMemory=newbyte[1000000];
14
15privateTestClassHasEvent_inject;
16
17publicTestListener(TestClassHasEventinject)
18{
19_inject=inject;
20_ent+=entHandler(_inject_YourEvent);
21}
22
23void_inject_YourEvent(objectsender,EventArgse)
24{
25
26}
27}
28
29classProgram
30{
31staticvoidDisplayMemory()
32{
ine("Totalmemory:{0:###,###,###,##0}bytes",alMemory(true));
34}
35
36staticvoidMain()
37{
38DisplayMemory();
ine();
40for(inti=0;i<5;i++)
41{
ine("---NewListener#{0}---",i+1);
43
44varlistener=newTestListener(newTestClassHasEvent());
45listener=null;//可有可⽆
46
t();
rPendingFinalizers();
t();
50DisplayMemory();
51
52}
();
54}
55}
改成:
看看运⾏结果:
内存泄露了
加个Dispose⼿动注销事件,然后使⽤Using关键字,就没有问题了
[csharp]
TestListener(TestClassHasEventinject)
2.{
3._inject=inject;
4._ent+=entHandler(_inject_YourEvent);
5.}
1publicTestListener(TestClassHasEventinject)
2{
3_inject=inject;
4_ent+=entHandler(_inject_YourEvent);
5}
[csharp]
TestListener(TestClassHasEventinject)
2.{
ySettingsChanged+=newEventHandler(SystemEvents_DisplaySettingsChanged);
4.}
5.
stemEvents_DisplaySettingsChanged(objectsender,EventArgse)
7.{
8.
9.}
1publicTestListener(TestClassHasEventinject)
2{
ySettingsChanged+=newEventHandler(SystemEvents_DisplaySettingsChanged);
4}
5
6voidSystemEvents_DisplaySettingsChanged(objectsender,EventArgse)
7{
8
9}
[csharp]
estListener:IDisposable
2.{
[]m_ExtraMemory=newbyte[1000000];
4.
eTestClassHasEvent_inject;
6.
TestListener(TestClassHasEventinject)
8.{
ySettingsChanged+=newEventHandler(SystemEvents_DisplaySettingsChanged);
10.}
11.
stemEvents_DisplaySettingsChanged(objectsender,EventArgse)
13.{
14.
15.}
16.
17.#regionIDisposableMembers
18.
voidDispose()
20.{
ySettingsChanged-=newEventHandler(SystemEvents_DisplaySettingsChanged);
22.}
23.
24.#endregion
25.}
26.
rogram
28.{
voidDisplayMemory()
30.{
ine("Totalmemory:{0:###,###,###,##0}bytes",alMemory(true));
32.}
33.
voidMain()
35.{
yMemory();
ine();
(inti=0;i<5;i++)
39.{
ine("---NewListener#{0}---",i+1);
41.
(varlistener=newTestListener(newTestClassHasEvent()))
43.{
44.//dosomething
45.}
t();
rPendingFinalizers();
t();
yMemory();
50.
50.
51.}
();
53.}
54.}
上⾯两个例⼦⼀个内存泄露,⼀个没有内存泄露,我想你应该知道原因了,根本区别在于后者有个
ySettingsChanged事件,这个事件是静态Static事件,所以绑定到这个事件上的对象都不会被释放
1classTestListener:IDisposable
2{
3byte[]m_ExtraMemory=newbyte[1000000];
4
5privateTestClassHasEvent_inject;
6
7publicTestListener(TestClassHasEventinject)
8{
ySettingsChanged+=newEventHandler(SystemEvents_DisplaySettingsChanged);
10}
11
12voidSystemEvents_DisplaySettingsChanged(objectsender,EventArgse)
13{
14
15}
16
17#regionIDisposableMembers
18
19publicvoidDispose()
20{
ySettingsChanged-=newEventHandler(SystemEvents_DisplaySettingsChanged);
22}
23
24#endregion
25}
26
27classProgram
28{
29staticvoidDisplayMemory()
30{
ine("Totalmemory:{0:###,###,###,##0}bytes",alMemory(true));
32}
33
34staticvoidMain()
35{
36DisplayMemory();
ine();
38for(inti=0;i<5;i++)
39{
ine("---NewListener#{0}---",i+1);
41
42using(varlistener=newTestListener(newTestClassHasEvent()))
43{
44//dosomething
45}
t();
rPendingFinalizers();
t();
49DisplayMemory();
50
51}
();
53}
54}
[csharp]
1.//Type:Events
2.//Assembly:System,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089
3.//Assemblylocation:C:meworkv4.0ProfileClientSys
4.
ystem;
entModel;
7.
32
9.{
sealedclassSystemEvents
11.{
staticIntPtrCreateTimer(intinterval);
staticvoidInvokeOnEventsThread(Delegatemethod);
staticvoidKillTimer(IntPtrtimerId);
staticeventEventHandlerDisplaySettingsChanging;
staticeventEventHandlerDisplaySettingsChanged;
staticeventEventHandlerEventsThreadShutdown;
staticeventEventHandlerInstalledFontsChanged;
19.
20.[EditorBrowsable()]
21.[Obsolete(":///fwlink/?linkid=14202")]
22.[Browsable(false)]
staticeventEventHandlerLowMemory;
24.
staticeventEventHandlerPaletteChanged;
staticeventPowerModeChangedEventHandlerPowerModeChanged;
staticeventSessionEndedEventHandlerSessionEnded;
staticeventSessionEndingEventHandlerSessionEnding;
staticeventSessionSwitchEventHandlerSessionSwitch;
staticeventEventHandlerTimeChanged;
staticeventTimerElapsedEventHandlerTimerElapsed;
staticeventUserPreferenceChangedEventHandlerUserPreferenceChanged;
staticeventUserPreferenceChangingEventHandlerUserPreferenceChanging;
34.}
35.}
注意Static,注意Singleton这种static的东西⽣命周期很长,永远不会被GC回收,⼀旦被他给引⽤上了,那就不可能释放了。上⾯的例⼦
就是ySettingsChanged+=newEventHandler(SystemEvents_DisplaySettingsChanged);那就意味着这个类
被ySettingsChanged引⽤了,通过它的函数。另外⼀个要注意的是Singleton单例模式实现的类,他们也是static
的⽣命周期很长,要注意引⽤链,你的类是否被它引⽤上,如果在它的引⽤链上,就内存泄露了。
另外还有注意程序运⾏期间不会释放的对象的事件
还有⼀种情况,既不是你的对象被static对象⽽不能释放,也不是Singleton,⽽是你的对象被⼀个永远不释放的对象引⽤着,这个对象或
许不是static的。这种类型很多,⽐如你的界⾯有个MainForm,嘿嘿,这个MainForm永远不会关闭和释放的,被它引⽤了那就不会释放
了。看个例⼦:
MainForm⾥⾯有个publicevent,MainForm⾥⾯打开Form2,然后关闭,看看Form2能不能释放:
1//Type:Events
2//Assembly:System,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089
3//Assemblylocation:C:
4
5usingSystem;
entModel;
7
32
9{
10publicsealedclassSystemEvents
11{
12publicstaticIntPtrCreateTimer(intinterval);
13publicstaticvoidInvokeOnEventsThread(Delegatemethod);
14publicstaticvoidKillTimer(IntPtrtimerId);
15publicstaticeventEventHandlerDisplaySettingsChanging;
16publicstaticeventEventHandlerDisplaySettingsChanged;
17publicstaticeventEventHandlerEventsThreadShutdown;
18publicstaticeventEventHandlerInstalledFontsChanged;
19
20[EditorBrowsable()]
21[Obsolete(":///fwlink/?linkid=14202")]
22[Browsable(false)]
23publicstaticeventEventHandlerLowMemory;
24
25publicstaticeventEventHandlerPaletteChanged;
26publicstaticeventPowerModeChangedEventHandlerPowerModeChanged;
27publicstaticeventSessionEndedEventHandlerSessionEnded;
28publicstaticeventSessionEndingEventHandlerSessionEnding;
29publicstaticeventSessionSwitchEventHandlerSessionSwitch;
30publicstaticeventEventHandlerTimeChanged;
31publicstaticeventTimerElapsedEventHandlerTimerElapsed;
32publicstaticeventUserPreferenceChangedEventHandlerUserPreferenceChanged;
33publicstaticeventUserPreferenceChangingEventHandlerUserPreferenceChanging;
34}
35}
[csharp]
partialclassMainForm:Form
2.{
eventPropertyChangedEventHandlerPropertyChanged;
4.
tedvirtualvoidOnPropertyChanged(stringpropertyName)
6.{
tyChangedEventHandlerhandler=PropertyChanged;
8.
(handler!=null)
r(this,newPropertyChangedEventArgs(propertyName));
11.}
12.
MainForm()
14.{
lizeComponent();
16.}
17.
evoidbutton1_Click(objectsender,EventArgse)
19.{
2frm=newForm2();
21.
tyChanged+=_PropertyChanged;
23.//MainFormreferencedform2,becausemainformisnotreleased,thereforeform2willnotreleased.
24.
Resultd=alog();
26.
t();
talMemory();
29.
30.}
31.
32.
33.
evoidShowTotalMemory()
35.{
(("Memory:{0:###,###,###,##0}bytes",alMemory(true)));
37.}
38.}
Form2⾥⾯有个函数:
1publicpartialclassMainForm:Form
2{
3publiceventPropertyChangedEventHandlerPropertyChanged;
4
5protectedvirtualvoidOnPropertyChanged(stringpropertyName)
6{
7PropertyChangedEventHandlerhandler=PropertyChanged;
8
9if(handler!=null)
10handler(this,newPropertyChangedEventArgs(propertyName));
11}
12
13publicMainForm()
14{
15InitializeComponent();
16}
17
18privatevoidbutton1_Click(objectsender,EventArgse)
19{
20Form2frm=newForm2();
21
tyChanged+=_PropertyChanged;
23//MainFormreferencedform2,becausemainformisnotreleased,thereforeform2willnotreleased.
24
25DialogResultd=alog();
26
t();
28ShowTotalMemory();
29
30}
31
32
33
34privatevoidShowTotalMemory()
35{
(("Memory:{0:###,###,###,##0}bytes",alMemory(true)));
37}
38}
[csharp]
partialclassForm2:Form
2.{
Form2()
4.{
lizeComponent();
6.}
voidfrm_PropertyChanged(objectsender,PropertyChangedEventArgse)
8.{
9.
10.}
11.}
所以这种情况下,你的Eventhandler没有⼿动注销,那就肯定内存泄露了。
2.静态变量
静态变量中的成员所占的内存不果不⼿动处理是不会释放内存的,单态模式的对象也是静态的,所以需要特别注意。因为静态对象中的成员
所占的内存不会释放,如果此成员是以个对象,同时此对象中的成员所占的内存也不会释放,以此类推,如果此对象很复杂,⽽且是静态的
就很容易造成内存泄露。
3.⾮托管资源
因为⾮托管资源所占的内存不能⾃动回收,所以使⽤后必须⼿动回收,否则程序运⾏多次很容易造成内存泄露
e⽅法没被调⽤,或Dispose⽅法没有处理对象的释放。这样也会造成内存泄露
5.当⼀个查询语句查询出来的数据量很⼤,达到⼏百万条数据时存放到datatable或dataset中也会造成内存溢出,这是可以采⽤分页查询
等其他⽅法来解决
1publicpartialclassForm2:Form
2{
3publicForm2()
4{
5InitializeComponent();
6}
7publicvoidfrm_PropertyChanged(objectsender,PropertyChangedEventArgse)
8{
9
10}
11}
更多推荐
framework 4 0 64位
发布评论