搜档网
当前位置:搜档网 › Delphi中可能你不知道的内存泄露

Delphi中可能你不知道的内存泄露

Delphi中可能你不知道的内存泄露
Delphi中可能你不知道的内存泄露

Delphi中可能你不知道的内存泄露

Delphi中可能你不知道的内存泄露

时间:2011-9-3 15:37:12 点击:

1437

核心提示:为了提高string 的读写性能Delphi 采用了copy-on-write 机制进行内存管理。简单来说,在复制一个string 时并不是真的在内存中把原来string 的内容复制一

份到另...为了提高string 的读写性能Delphi 采用了

copy-on-write 机制进行内存管理。简单来说,在复制一个string 时并不是真的在内存中把原来string 的内容复制一

份到另外一个地址,而是把新的string 在内存映射表中指向同原string 相同的位置,并且把那块内存的引用计数加一。这样就省去了复制字符串的时间。只有当string 的内容发生变化的时候,才真正将改动的内容完整复制一份到新的地址,然后对原地址的引用计数减一,将新地址的引用计数设为一,最后将新string 在内存映射表中指向这个新的位置。当某个字符串内存块的引用计数为零了,这块内存就可以被其它程序使用了。注意:所有常量string 会在编译时率先分配内存,其引用计数不会在程序中变化,始终为-1。更详细的介绍,

可以参考『Pascal 精要』和『标准C++类std::string的内存共享和Copy-On-Write技术』。

内存泄漏的发现:

在检查内存泄漏时,无意发现了使用记录过程中产生的内存泄漏。请看如下代码:

type

TMyRec = record

S: string;

I: Integer;

end;

procedure Test;

var

ARec: TMyRec;

begin

FillChar(ARec, SizeOf(ARec), #0);

ARec.S := 'abcd';

ARec.I := 1234;

// ...

FillChar(ARec, SizeOf(ARec), #0); //<--- A leak!

// ...

end;

FillChar 的作用是对一个内存块进行连续赋值,内存泄漏出

现在第二次调用FillChar 的时候。经过调试后发现:如果把记录中的string 字段改成Pchar??或者删除,就不再有内存泄漏了。

原因分析:

我们现在先了解一下记录在内存中是如何分配的。记录是个不同数据类型的集合体。记录长度就是每个字段的内存长度之和。注意,该长度在编译之前就已经是确定的。因此那些长度不定的类型(如string、对象) 都是以指针形式出现在记录中。我的分析是:由于FillChar 是低级内存读写操作,它仅仅把记录所占的内存块清掉,但没通知编译器更新字符串的引用计数,因而造成了泄漏。请看如下代码:

function StringStatus(const S: string): string;

begin

Result :=

Format('Addr: %p, RefCount: %d, Value: %s',

[Pointer(S),

PInteger(Integer(S) - 4)^, // length

PInteger(Integer(S) - 8)^,

S]);

end;

procedure BadExample1;

var

S1: string;

ARec: TMyRec;

begin

S1 := Copy('string', 1, 6); // Force allocates memory for the string

WriteLn(StringStatus(S1));

ARec.S := S1;

WriteLn(StringStatus(ARec.S));

FillChar(ARec, SizeOf(ARec), #0);

WriteLn(StringStatus(S1));

end;

Addr: 00E249E8, RefCount: 1, Value: string // OK: Allocated as a new string

Addr: 00E249E8, RefCount: 2, Value: string // OK: RefCount increated

Addr: 00E249E8, RefCount: 2, Value: string // !!! RefCount UN-changed!!!

在执行FillChar 之前,字符串S1 的引用计数是2,但是执行FillChar 之后并没有减1。这段代码验证了我的推测:FillChar 操作可能会破坏字符串的Copy-On-Write 机制,使用的时候需要倍加小心!

进一步分析:

文章开头我提到“所有有常量string 会在编译时率先分配内存,其引用计数不会在程序中变化,始终为-1。“ 那么如果我们让S1 和ARec.S 都赋值为一个常量字符串,那么照理说就不用管引用计数,也就没有泄漏问题了。请接着看下面这个例子:

procedure BadExample2;

var

S1: string;

ARec: TMyRec;

begin

S1 := 'string'; // Assigns S1 to a const (compiler time allocated) string

WriteLn(StringStatus(S1));

ARec.S := S1;

WriteLn(StringStatus(ARec.S));

FillChar(ARec, SizeOf(ARec), #0);

WriteLn(StringStatus(S1));

end;

Addr: 0040CCBC, RefCount: -1, Value: string // OK: RefCount UN-changed

Addr: 00E24B08, RefCount:??1, Value: string // !!! Allocated as a new string !!!

Addr: 0040CCBC, RefCount: -1, Value: string // OK: RefCount UN-changed

结果是不是很吃惊,赋值ARec.S 的时候,并没有直接将其指向常量字符串,而是重新分配了一个新的字符串。由此可见,记录在对字符串赋值上是有问题的!

解决方法:

既然知道使用FillChar 来初始化记录是不安全的,那么我们是不是要回到解放前,手动对记录进行初始化呢?也不用。Delphi 有个保留字out。它和var、const 一样,是用来修饰函数参数的。它和var 的功能相似,不同是,它会对那些以指针形式传入的变量先进行引用计数清理。Delphi 的帮助中解释道:An out parameter, like a variable parameter, is passed by reference. With an out parameter, however, the initial value of the referenced variable is discarded by the routine it is passed to. The out parameter is for output only; that is, it tells the function or procedure where to store output, but doesn't provide any input.

哈哈,这个不正是FillChar 想要但又做不到的吗?于是我改造了一个InitializeRecord 来初始化记录。

procedure InitializeRecord(out ARecord; count: Integer); begin

FillChar(ARecord, count, #0);

end;

仅仅是多了一层函数嵌套,内存泄漏问题就解决了。多亏了这个神奇的out!

我们来仔细看看加了out 之后,编译器到底做了什么?mov edx,[$0040c904]

mov eax,ebx

call @FinalizeRecord //<----- cleanup

mov edx,$0000000c

call InitializeRecord

关键就是第三行调用了FinalizeRecord。这是System.pas 中的一个汇编函数,作用就是对记录做一下清理工作。如果你想探个究竟,可以查看一下这个函数是如何实现的。这里就不作详解了。

想法总结:

没想到一个偶然的发现,竟可以带出这么多问题,真是因祸得福。我总价一下几点想法

FillChar 是低级的内存读写,所以在使用之前你要非常清楚要打算干什么。

在记录类型中慎用string 和Widestring。如果记录的结构复杂,不妨尝试封装成类,类可以提供更丰富的特性,扩展性更佳。如果一定要定义带string 的记录,最好注释一下,以免日后出错。(有时候的确是记录更方便和高效)

活用out 保留字可以解决接口类型和带string 的记录类型的引用计数问题。

--------------------------------------------------------------------------------------------------------刘啸

拿生成的汇编对比一下更有说服力:

procedure SafeFillChar(var Value: TMyRec);

begin

FillChar(Value, SizeOf(Value), #0);

end;

它的汇编代码实际上为:

Unit1.pas.50: FillChar(Value, SizeOf(Value), #0);

0044C91C 33C9 xor ecx,ecx

0044C91E BA08000000 mov edx,$00000008

0044C923 E8CC61FBFF call @FillChar

Unit1.pas.51: end;

0044C928 C3 ret

比较简单,直接Call FillChar了。

而如果是out的话:

procedure SafeFillChar(out Value: TMyRec); begin

FillChar(Value, SizeOf(Value), #0);

end;

生成的代码会复杂一点:

Unit1.pas.49: begin

0044C928 55 push ebp

0044C929 8BEC mov ebp,esp

0044C92B 53 push ebx

0044C92C 8BD8 mov ebx,eax

0044C92E 8BC3 mov eax,ebx

0044C930 8B156CC84400 mov edx,[$0044c86c] 0044C936 E8417EFBFF call @InitializeRecord Unit1.pas.50: FillChar(Value, SizeOf(Value), #0); 0044C93B 8BC3 mov eax,ebx

0044C93D 33C9 xor ecx,ecx

0044C93F BA08000000 mov edx,$00000008 0044C944 E8AB61FBFF call @FillChar

Unit1.pas.51: end;

0044C949 5B pop ebx

0044C94A 5D pop ebp

0044C94B C3 ret

这里的关键就是有个call @InitializeRecord,把传入的记录中的字符串安全清空了。所以不会导致内存泄漏。

总结一句:out修饰符不光是忽视传入参数,还会手工先把传入参数清一把。

-------------------------------------------------------------------------------------------------------------jAmEs_

发表于2007-7-21 10:45 资料文集短消息

我的看法:

這樣的內存泄露說法好像說不過去,只能說record類型帶string本不應該采用FillChar來初始化資源~~。

就好像,無論你的程序多么嚴密,你通過非正常手段故意把內存地址的值改變為空,然后導致程序不再去釋放(假設判斷為空不是否),然后你說內存泄露了。。。

不過SafeFillChar做法倒是一個的技巧。

-------------------------------------------------------------------------------------------------------------刘啸

发表于2007-7-21 21:42 资料文集短消息

本文说的正是非正常手段导致的内存泄漏。

这种非正常的手段在有些朋友写的程序中可能会出现。

-------------------------------------------------------------------------------------------------------------小冬

再加一个,如果像源作者这样字义只可以初始化一种结构变

量TMyRec。

procedure SafeFillChar(out Value:

{FILLCHAR_ILLEGAL}TMyRec);

begin

FillChar(Value, SizeOf(Value), #0);

end;

但是,如果我们像FillChar那样定义就可以初始化所有结构变量。不错吧?

procedure SafeFillChar(out Value);

begin

FillChar(Value, SizeOf(Value), #0);

end;

-----------------------------------------------------------------------------

---------------------------------刘啸

对楼上的问题:

一、如果out Value是个无类型变量的话,sizeof(Value)会

是真正传入的记录的size吗,还是只是一个指针的长度?二、Delphi是否知道它是record而去调用@InitializeRecord?我觉得不会。

-----------------------------------------------------------------------------

----------------------------------小冬

我查过帮助,D本身的FillChar也是这样定义procedure

FillChar(var X; Count: Integer; Value: Byte);

---------------------------------------------------------------------------------------------------------------刘啸

FillChar是传入了var X,但它同时传了一个Count。

无类型变量var X作为参数传入是可以的,

但其实际长度如果不传入的话,在函数体内部是无法通过sizeof来得到的。

----------------------------------------------------------------------------------------------------------------小冬

再改一下:

procedure SafeFillChar(out X; Count: Integer; V: Byte); begin

FillChar(X, Count, V);

end;

-----------------------------------------------------------------------------------------------------------------刘啸

不对吧两位,楼主和小冬改的SafeFillChar是能完成FillChar 的功能,

但没了“因为存在record而由Delphi预先调用InitializeRecord”的机制,

那便真的和FillChar一模一样了。

-----------------------------------------------------------------------------

------------------------------------刘啸

我说的也不对。虽然没了“因为存在record而由Delphi预先调用InitializeRecord”的机制,但可能存在“因为存在out而

由Delphi预先调用FinallizeRecord”的机制,也会自动清除引用计数导致一切正常。

这俩机制虽然不一样,但刚好都被我们碰上了。Delphi中可能你不知道的内存泄露

时间:2011-9-3 15:37:12 点击:

1437

核心提示:为了提高string 的读写性能Delphi 采用了copy-on-write 机制进行内存管理。简单来说,在复制一个string 时并不是真的在内存中把原来string 的内容复制一

份到另...为了提高string 的读写性能Delphi 采用了

copy-on-write 机制进行内存管理。简单来说,在复制一个string 时并不是真的在内存中把原来string 的内容复制一

份到另外一个地址,而是把新的string 在内存映射表中指向同原string 相同的位置,并且把那块内存的引用计数加一。这样就省去了复制字符串的时间。只有当string 的内容发生变化的时候,才真正将改动的内容完整复制一份到新的地址,然后对原地址的引用计数减一,将新地址的引用计数设为一,

最后将新string 在内存映射表中指向这个新的位置。当某个字符串内存块的引用计数为零了,这块内存就可以被其它程序使用了。注意:所有常量string 会在编译时率先分配内存,其引用计数不会在程序中变化,始终为-1。更详细的介绍,可以参考『Pascal 精要』和『标准C++类std::string的内存共享和Copy-On-Write技术』。

内存泄漏的发现:

在检查内存泄漏时,无意发现了使用记录过程中产生的内存泄漏。请看如下代码:

type

TMyRec = record

S: string;

I: Integer;

end;

procedure Test;

var

ARec: TMyRec;

begin

FillChar(ARec, SizeOf(ARec), #0);

ARec.S := 'abcd';

ARec.I := 1234;

// ...

FillChar(ARec, SizeOf(ARec), #0); //<--- A leak!

// ...

end;

FillChar 的作用是对一个内存块进行连续赋值,内存泄漏出现在第二次调用FillChar 的时候。经过调试后发现:如果把记录中的string 字段改成Pchar??或者删除,就不再有内存泄漏了。

原因分析:

我们现在先了解一下记录在内存中是如何分配的。记录是个不同数据类型的集合体。记录长度就是每个字段的内存长度之和。注意,该长度在编译之前就已经是确定的。因此那些长度不定的类型(如string、对象) 都是以指针形式出现在记录中。我的分析是:由于FillChar 是低级内存读写操作,它仅仅把记录所占的内存块清掉,但没通知编译器更新字符串的引用计数,因而造成了泄漏。请看如下代码:

function StringStatus(const S: string): string;

begin

Result :=

Format('Addr: %p, RefCount: %d, Value: %s',

[Pointer(S),

PInteger(Integer(S) - 4)^, // length

PInteger(Integer(S) - 8)^,

S]);

end;

procedure BadExample1;

var

S1: string;

ARec: TMyRec;

begin

S1 := Copy('string', 1, 6); // Force allocates memory for the string

WriteLn(StringStatus(S1));

ARec.S := S1;

WriteLn(StringStatus(ARec.S));

FillChar(ARec, SizeOf(ARec), #0);

WriteLn(StringStatus(S1));

end;

Addr: 00E249E8, RefCount: 1, Value: string // OK: Allocated as a new string

Addr: 00E249E8, RefCount: 2, Value: string // OK: RefCount increated

Addr: 00E249E8, RefCount: 2, Value: string // !!! RefCount UN-changed!!!

在执行FillChar 之前,字符串S1 的引用计数是2,但是执行FillChar 之后并没有减1。这段代码验证了我的推测:FillChar 操作可能会破坏字符串的Copy-On-Write 机制,使用的时候需要倍加小心!

进一步分析:

文章开头我提到“所有有常量string 会在编译时率先分配内存,其引用计数不会在程序中变化,始终为-1。“ 那么如果我们让S1 和ARec.S 都赋值为一个常量字符串,那么照理说就不用管引用计数,也就没有泄漏问题了。请接着看下面这个例子:

procedure BadExample2;

var

S1: string;

ARec: TMyRec;

begin

S1 := 'string'; // Assigns S1 to a const (compiler time allocated) string

WriteLn(StringStatus(S1));

ARec.S := S1;

WriteLn(StringStatus(ARec.S));

FillChar(ARec, SizeOf(ARec), #0);

WriteLn(StringStatus(S1));

end;

Addr: 0040CCBC, RefCount: -1, Value: string // OK: RefCount UN-changed

Addr: 00E24B08, RefCount:??1, Value: string // !!! Allocated as a new string !!!

Addr: 0040CCBC, RefCount: -1, Value: string // OK: RefCount UN-changed

结果是不是很吃惊,赋值ARec.S 的时候,并没有直接将其指向常量字符串,而是重新分配了一个新的字符串。由此可见,记录在对字符串赋值上是有问题的!

解决方法:

既然知道使用FillChar 来初始化记录是不安全的,那么我们是不是要回到解放前,手动对记录进行初始化呢?也不用。Delphi 有个保留字out。它和var、const 一样,是用来修饰函数参数的。它和var 的功能相似,不同是,它会对那些以指针形式传入的变量先进行引用计数清理。Delphi 的帮助中解释道:An out parameter, like a variable parameter, is passed by reference. With an out parameter, however, the initial value of the referenced variable is discarded by the routine it is passed to. The out parameter is for output only;

that is, it tells the function or procedure where to store output, but doesn't provide any input.

哈哈,这个不正是FillChar 想要但又做不到的吗?于是我改造了一个InitializeRecord 来初始化记录。

procedure InitializeRecord(out ARecord; count: Integer); begin

FillChar(ARecord, count, #0);

end;

仅仅是多了一层函数嵌套,内存泄漏问题就解决了。多亏了这个神奇的out!

我们来仔细看看加了out 之后,编译器到底做了什么?mov edx,[$0040c904]

mov eax,ebx

call @FinalizeRecord //<----- cleanup

mov edx,$0000000c

call InitializeRecord

关键就是第三行调用了FinalizeRecord。这是System.pas 中的一个汇编函数,作用就是对记录做一下清理工作。如果你想探个究竟,可以查看一下这个函数是如何实现的。这里就不作详解了。

想法总结:

没想到一个偶然的发现,竟可以带出这么多问题,真是因祸得福。我总价一下几点想法

FillChar 是低级的内存读写,所以在使用之前你要非常清楚要打算干什么。

在记录类型中慎用string 和Widestring。如果记录的结构复杂,不妨尝试封装成类,类可以提供更丰富的特性,扩展性更佳。如果一定要定义带string 的记录,最好注释一下,以免日后出错。(有时候的确是记录更方便和高效)

活用out 保留字可以解决接口类型和带string 的记录类型的引用计数问题。

--------------------------------------------------------------------------------------------------------刘啸

拿生成的汇编对比一下更有说服力:

procedure SafeFillChar(var Value: TMyRec);

begin

FillChar(Value, SizeOf(Value), #0);

end;

它的汇编代码实际上为:

Unit1.pas.50: FillChar(Value, SizeOf(Value), #0);

0044C91C 33C9 xor ecx,ecx

0044C91E BA08000000 mov edx,$00000008

0044C923 E8CC61FBFF call @FillChar

内存泄露问题定位

内存泄露问题定位 The Standardization Office was revised on the afternoon of December 13, 2020

一、现象 进行24用户的常保,出现region1 bucket0的内存泄露,大概20分钟泄露1000个,保持3小时后内存耗尽,造成宕机。 二、定位方法 CCPU的内存分配机制如下: CCPU对于内存的处理,是采用事先划分好一大块静态内存区,供软件使用。其划分 对于内存分配,如果待分配的内存大小介于Bucket内存四种块大小之内,就使用相应的Bucket内存去分配;如果待分配的内存大小超出了Bucket内存最大块的大小,则使用Heap内存分配。 打开之前的定位内存泄露问题的宏开关,控制台出现大量打印。无法定位问题。 经分析,每块内存的分配回收的历史信息其实没有必要保存,只需要保留最后一个分配的情况即可。在每个块中,内存的管理其实是一个数组,用一个链表来记录未分配的内存块。根据这个原理,在分配、回收内存时可以得到该内存块在bucket中的索引。例如region1 bucket0有内存泄露,则分配一个10000的数组记录每个内存元素的分配回收情况。保存该内存元素当前是分配还是回收,最后分配的文件名行号。最后将这些信息输出到文件里。这种方法可以用于定位任何bucket的内存泄露,并且不需要PC侧的解析工具。 经过使用该方法分析,泄露的内存都是由解析上行语音包时分配的。 三、内存泄漏原因 下面分析这些内存为什么会泄露,经过初步走读代码在出现异常又没有释放内存时增加打印,但是进行常保测试没有出现这些打印。 在申请内存和数据包到达MAC时分别进行统计,发现申请内存的次数多于数据包到达MAC层的次数。 继续走查申请内存到数据包传递到MAC之间的代码,发现当tfi=0时也会申请内存,但后续因为计算出的TB个数为0,所以并没有得到处理,从而导致内存泄露。 四、结论 当用户数较多时会收到tfi为0的上行数据包,而代码中对这种情况的处理有问题。解决办法:在申请内存之前判断TB块总长度是否为0,如果为0则直接返回,不申请内存。

电脑内存不足及释放内存

第一招:关闭多余顺序 如果同时打开地文档过多或者运行地顺序过多,就没有足够地内存运行其他顺序.这时,对于多文档界面程序,如等,请关闭当前文档外地所有文档,并退出当前未使用地顺序,或许你就能够继续执行因“内存缺乏”而被中断地任务.资料个人收集整理,勿做商业用途 第二招:清除剪贴板中地内容 .清除系统剪贴板中地内容(存储复制或剪贴内容地剪贴板)点击“开始→顺序→附件→系统工具→剪贴板查看程序”编辑”菜单上,单击“删除”命令,系统弹出“清除剪贴板”对话框,单击“按钮.资料个人收集整理,勿做商业用途 .清除多重剪贴板中地内容(顺序提供地剪贴板)剪贴板”任务窗格(或工具栏(上,单击“全部清空”或“清空‘剪贴板’当清空“剪贴板”时,系统剪贴板也将同时被清空.资料个人收集整理,勿做商业用途 第三招:合理设置虚拟内存 如果没有设置虚拟内存,那么很容易收到内存缺乏”消息.点击“开始→设置→控制面板”双击“系统”系统属性”对话框中,单击“性能”选项卡,然后单击“虚拟内存”按钮.选中“让管理虚拟内存设置推荐)选项,将计算机中可作为虚拟内存使用地硬盘空间量设置为默认值.资料个人收集整理,勿做商业用途 第四招:增加可用磁盘空间 有四种方法可以增加磁盘地使用空间: .清空回收站. .删除临时文件.打开电脑”右键单击要释放其空间地磁盘,然后单击“属性”惯例”选项卡上,单击“磁盘清理”按钮,选中要删除地不需要地文件前地复选框进行整理.资料个人收集整理,勿做商业用途 .从磁盘中删除过期地文件或已存档地文件. .删除从未使用过地所有文件. 第五招:重新装置已损坏地顺序 如果仅仅是使用某个顺序时,系统提示内存缺乏,而其他顺序可以正常运行,那么可能地原因是该顺序文件被毁坏,从而导致内存缺乏地问题.请尝试删除偏重新安装该程序,然后重新运行该程序.如果系统不再提示内存缺乏,那么说明原顺序文件确实被损坏.资料个人收集整理,勿做商业用途 第六招:使用内存优化软件 内存优化软件有很多,比方和就比较出色.可以设置自动清空剪贴板、释放被关闭顺序未释放地内存,从而免除你手工操作地麻烦,达到自动释放内存地目地无妨一试.资料个人收集整理,勿做商业用途 第七招:重新启动计算机 如果只退出程序,并不重新启动计算机,顺序可能无法将内存资源归还给系统.运行重要顺序之前,请重新启动计算机以充分释放系统资源.资料个人收集整理,勿做商业用途 第八招:减少自动运行地顺序 如果在启动时自动运行地顺序太多,那么,即使重新启动计算机,也没足够地内存用来运行其他顺序.这时就需要清除一些不必要地系统自启动程序.点击“开始→运行”输入打开“系统配置实用顺序”窗口.单击“一般”选项卡,选中“选择性启动”复选框.去掉处置文件”和“加载启动项”前地复选框.打开“启动”选项卡,将不需要开机自动启动地顺序都勾除掉就好了资料个人收集整理,勿做商业用途 第九招:查杀病毒 系统感染电脑病毒也是导致内存缺乏地罪魁祸首.当系统出现“内存缺乏”错误时,请使用最

02-内存管理

1.怎么保证多人开发进行内存泄露的检查. 1>使用Analyze进行代码的静态分析 2>为避免不必要的麻烦, 多人开发时尽量使用ARC 2.非自动内存管理情况下怎么做单例模式. 创建单例设计模式的基本步骤· >声明一个单件对象的静态实例,并初始化为nil。 >创建一个类的类工厂方法,当且仅当这个类的实例为nil时生成一个该类的实例>实现NScopying协议, 覆盖allocWithZone:方法,确保用户在直接分配和初始化对象时,不会产生另一个对象。 >覆盖release、autorelease、retain、retainCount方法, 以此确保单例的状态。>在多线程的环境中,注意使用@synchronized关键字或GCD,确保静态实例被正确的创建和初始化。 3.对于类方法(静态方法)默认是autorelease的。所有类方法都会这样吗? 1> 系统自带的绝大数类方法返回的对象,都是经过autorelease的 4.block在ARC中和MRC中的用法有什么区别,需要注意什么 1.对于没有引用外部变量的Block,无论在ARC还是非ARC下,类型都是__NSGlobalBlock__,这种类型的block可以理解成一种全局的block,不需要考虑作用域问题。同时,对他进行Copy或者Retain操作也是无效的 2.应注意避免循环引用 5.什么情况下会发生内存泄漏和内存溢出? 当程序在申请内存后,无法释放已申请的内存空间(例如一个对象或者变量使用完成后没有释放,这个对象一直占用着内存),一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。内存泄露会最终会导致内存溢出! 当程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个int,但给它存了long才能存下的数,那就是内存溢出。 6.[NSArray arrayWithobject:] 这个方法添加对象后,需要对这个数组做释放操作吗? 不需要这个对象被放到自动释放池中 7.Json数据的解析,和解析数据的时候有内存泄露吗?有的话如何解 1>JSON解析的方案 ●SBJson ●JSONkit ●NSJSONSerialization 2>内存泄漏么?

内存泄漏检查

内存泄漏检测方法 ?对于不同的程序可以使用不同的方法来进行内存泄漏的检查,还可以使用一些专门的工具来进行内存问题的检查,例如MemProof、AQTime、Purify、BundsChecker 等。 ?也可以使用简单的办法:利用Windows自带的Perfmon来监控程序进程的handle count、Virtual Bytes和Working Set 3个计数器。 Handle Count记录了进程当前打开的句柄个数,监视这个计数器有助于发现程序是否存在句柄类型的内存泄漏; Virtual Bytes记录了程序进程在虚拟地址空间上使用的虚拟内存的大小,Virtual Bytes一般总大于程序的Working Set,监视Virtual Bytes可以帮助发现一些系统底层的问题; Working Set记录了操作系统为程序进程分配的内存总量,如果这个值不断地持续增加,而Virtual Bytes却跳跃式地增加,则很可能存在内存泄漏问题。 堆栈内存泄漏 ?堆栈空间不足会导致在受托管的情况下引发StackOverflowException类型的异常,线程泄漏是堆栈内存泄漏的其中一种。线程发生泄漏,从而使线程的整个堆栈发生泄漏。 ?如果应用程序为了执行后台工作而创建了大量的工作线程,但却没有正常终止这些线程,则可能会引起线程泄漏。 一个堆栈内存泄漏的例子: private void button1_Click(object sender, EventArgs e) { // 循环启动多个线程 for (int i = 0; i < 1500; i++) { Thread t = new Thread(new ThreadStart(ThreadProc)); t.Start(); } } static void ThreadProc() { Console.WriteLine("启动Thread #{0}

Js内存泄漏及解决方案

Js内存泄漏及解决方案 在IE下的JS编程中,以下的编程方式都会造成即使关闭IE也无法释放内存的问题,下面分类给出: 1、给DOM对象添加的属性是一个对象的引用。范例: var MyObject = {}; document.getElementById('myDiv').myProp = MyObject; 解决方法: 在window.onunload事件中写上: document.getElementById('myDiv').myProp = null; 2、DOM对象与JS对象相互引用。范例: function Encapsulator(element) { this.elementReference = element; element.myProp = this; } new Encapsulator(document.getElementById('myDiv')); 解决方法: 在onunload事件中写上: document.getElementById('myDiv').myProp = null; 3、给DOM对象用attachEvent绑定事件。范例: function doClick() {} element.attachEvent("onclick", doClick); 解决方法: 在onunload事件中写上: element.detachEvent('onclick', doClick); 4、从外到内执行appendChild。这时即使调用removeChild也无法释放。范例: var parentDiv = document.createElement("div"); var childDiv = document.createElement("div"); document.body.appendChild(parentDiv); parentDiv.appendChild(childDiv); 解决方法: 从内到外执行appendChild: var parentDiv = document.createElement("div"); var childDiv = document.createElement("div"); parentDiv.appendChild(childDiv); document.body.appendChild(parentDiv); 5、反复重写同一个属性会造成内存大量占用(但关闭IE后内存会被释放)。范例: for(i = 0; i < 5000; i++) { hostElement.text = "asdfasdfasdf";

IIS内存溢出报错解决方案(一)

项目进行SSB改造以后,当客户端从服务器抓起大笔数据的时候,服务器报一个二进制流的错误,这个错误其实是一个内存溢出的错误。 提纲 故障现象 故障分析与解决 Code Review 工具与方法 故障现象 用户反映在进行数据导出时经常出现下面的错误:输入流是无效的二进制格式。开始内容(以字节为单位)是: 53-79-73-74-65-6D-2E-4F-75-74-4F-66-4D-65-6D-6F-72... 坏┏鱿指么砦蠛?/SPAN>,其他后面导出的用户都会出现该错误,导致无法进行操作。 故障分析 System.OutOfMemoryException 发生 53-79-73-74-65-6D-2E-4F-75-74-4F-66-4D-65-6D-6F-72... System.OutOfMemor ... System.OutOfMemoryException 发生的两种情况 应用程序消耗了过多的内存 内存碎片过多 内存Dump分析

有446M的free内存, 但最大的free内存块只有26M 不足64M 。内存碎片问题。 -------------------- Type SUMMARY -------------------------- TotSize ( KB) Pct(Tots) Usage 1b450000 ( 446784) : 21.30% : c940000 ( 206080) : 09.83% : MEM_IMAGE a3c000 ( 10480) : 00.50% : MEM_MAPPED 57824000 ( 1433744) : 68.37% : MEM_PRIVATE -------------------- State SUMMARY -------------------------- TotSize ( KB) Pct(Tots) Usage 2a82f000 ( 696508) : 33.21% : MEM_COMMIT 1b450000 ( 446784) : 21.30% : MEM_FREE 3a371000 ( 953796) : 45.48% : MEM_RESERVE Largest free region: Base 58bb0000 - Size 019f0000 (26560 KB) 内存中最大的一个dataset占用了18M内存,查看内容就是出现异常的导功能的内容sizeof(18e6a408) = 18,437,260 ( 0x119548c) bytes (System.Data.DataSet) … sizeof(18e6a8e0) = 18,437,260 ( 0x119548c) bytes (System.Data.DataTable) 系统中一共加载了6000多种Class,其中有3000多种是 0x0ff286b4 1 32 1 0x0ff2858c 1 32 1 0x0ff28464 1 32 1 0x0ff2833c 1 32 1 0x0ff28214 1 32 1 0x0ff280ec 1 32 1 0x0ff27fc4 1 32 1 0x0ff27e9c 1 32 1 0x0ff27d74 1 32 1 0x0ff27c4c 1 32 1 IIS日志分析 平均每天点击数:502,708 一共有 5,525 个IP访问过系统,平均每天有2,658 个访问 最大点击发生在 2007-11-19 达到 2,481,749次

JAVA内存溢出解决方案

JAVA内存溢出 解决方案 1. 内存溢出类型 1.1. https://www.sodocs.net/doc/a011025302.html,ng.OutOfMemoryError: PermGen space JVM管理两种类型的内存,堆和非堆。堆是给开发人员用的上面说的就是,是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的。它和堆不同,运行期内GC不会释放空间。如果web app用了大量的第三方jar或者应用有太多的class文件而恰好MaxPermSize设置较小,超出了也会导致这块内存的占用过多造成溢出,或者tomcat热部署时侯不会清理前面加载的环境,只会将context更改为新部署的,非堆存的内容就会越来越多。 PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。 一个最佳的配置例子:(经过本人验证,自从用此配置之后,再未出现过tomcat死掉的情况) set JAVA_OPTS=-Xms800m -Xmx800m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m 1.2. https://www.sodocs.net/doc/a011025302.html,ng.OutOfMemoryError: Java heap space 第一种情况是个补充,主要存在问题就是出现在这个情况中。其默认空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。如果内存剩余不到40%,JVM就会增大堆到Xmx设置的值,内存剩余超过70%,JVM就会减小堆到Xms设置的值。所以服务器的Xmx和Xms设置一般应该设置相同避免每次GC后都要调整虚拟机堆的大小。假设物理内存无限大,那么JVM内存的最大值跟操作系统有关,一般32位机是1.5g到3g之间,而64位的就不会有限制了。

几个内存泄漏的例子

几个内存泄漏的例子 ?new和delete要成对使用 ?new和delete要匹配 经常看到一些C++方面的书籍中这样提及到内存泄漏问题,这样的说法的意思是比较明白,但对于初学C++程序员还是很难掌握,所以下面举几个反面的例子,希望对大家有帮助。 例一:错误处理流程中的return导致的内存泄漏 bool MyFun() { CMyObject* pObj = NULL; pObj = new CMyObject(); … if (…) return false; … if(…) return false; … if (pObj != NULL) delete pObj; return true; } 注意:红色字体部分的return之前没有释放pObj,导致内存泄漏。 例二:exception改变了程序的正常流程,导致内存泄漏 情况1: HRESULT MyFun() { HRESULT hr = S_OK; try { CMyObject* pObj = NULL; pObj = new CMyObject(); … if (…) { hr = E_FAIL; throw hr; } … if(…) {

hr = E_FAIL; throw hr; } … if (pObj != NULL) delete pObj; } catch (HRESULT& eHr) { } return hr; } 情况2: void OtherFun() // 可能是自己写的其他函数; // 也可能是其他人写的函数; // 也可能是系统的API; { … if(…) throw exception; … } bool MyFun() { CMyObject* pObj = NULL; pObj = new CMyObject(); … OtherFun(); … if (pObj != NULL) delete pObj; return true; } 注意:上面的两种情况中的throw行为将导致程序的正常流程,一旦有throw的动作发生,pObj对象将不会被正确释放(delete)。 例三:忘记释放系统API创建的资源,导致内存泄露 bool CMyClass::MyFun() { HANDLE hHandle = CreateEvent(NULL,FALSE,TRUE,NULL); … if (…)

weblogic内存溢出解决方法

彻底解决Weblogic报出https://www.sodocs.net/doc/a011025302.html,ng.OutOfMemoryError: PermGen space问题: 打开域下面的bin目录(D:\Oracle\Middleware\user_projects\domains\base_domain\bin)。 编辑setDomainEnv.cmd文件,将以下蓝色的地方设置内存大小改成自己需要的。 set WLS_HOME=%WL_HOME%\server if "%JA V A_VENDOR%"=="Sun" ( set WLS_MEM_ARGS_64BIT=-Xms256m -Xmx512m set WLS_MEM_ARGS_32BIT=-Xms256m -Xmx512m ) else ( set WLS_MEM_ARGS_64BIT=-Xms512m -Xmx512m set WLS_MEM_ARGS_32BIT=-Xms512m -Xmx512m ) set MEM_ARGS_64BIT=%WLS_MEM_ARGS_64BIT% set MEM_ARGS_32BIT=%WLS_MEM_ARGS_32BIT% if "%JA V A_USE_64BIT%"=="true" ( set MEM_ARGS=%MEM_ARGS_64BIT% ) else ( set MEM_ARGS=%MEM_ARGS_32BIT% ) set MEM_PERM_SIZE_64BIT=-XX:PermSize=128m set MEM_PERM_SIZE_32BIT=-XX:PermSize=48m if "%JA V A_USE_64BIT%"=="true" ( set MEM_PERM_SIZE=%MEM_PERM_SIZE_64BIT% ) else ( set MEM_PERM_SIZE=%MEM_PERM_SIZE_32BIT% ) set MEM_MAX_PERM_SIZE_64BIT=-XX:MaxPermSize=256m set MEM_MAX_PERM_SIZE_32BIT=-XX:MaxPermSize=128m

JAVA内存泄露专题

内存泄露与内存溢出 1定义 1、内存泄漏:一般可以理解为系统资源(各方面的资源,堆、栈、线程等)在错误使用的情况下,导致使用完毕的资源无法回收(或没有回收),从而造成那部分内存不可用的情况。 2、内存溢出:指内存不够使用而抛出异常,内存泄露是其形成的原因之一。 2危害 会导致新的资源分配请求无法完成,引起系统错误,最后导致系统崩溃。 3内存泄漏分类 4 内存泄露/溢出发生的区域

5内存溢出异常 6内存溢出常见原因 7发生内存泄露的情形Java内存泄露根本原因是什么呢?

答:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。 具体主要有如下几大类: 7.1 静态集合类引起内存泄露 像HashMap、Vector等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,他们所引用的所有的对象Object也不能被释放,因为他们也将一直被Vector等引用着。 例: 解析: 在这个例子中,循环申请Object 对象,并将所申请的对象放入一个Vector 中,如果仅仅释放引用本身(o=null),那么Vector 仍然引用该对象,所以这个对象对GC 来说是不可回收的。因此,如果对象加入到Vector 后,还必须从Vector 中删除,最简单的方法就是将Vector对象设置为null。 7.2创建过大对象

以上代码运行时瞬间报错。 7.3监听器 在java 编程中,我们都需要和监听器打交道,通常一个应用当中会用到很多监听器,我们会调用一个控件的诸如addXXXListener()等方法来增加监听器,但往往在释放对象的时候却没有记住去删除这些监听器,从而增加了内存泄漏的机会。 7.4 各种连接 比如数据库连接(dataSourse.getConnection()),网络连接(socket)和io连接,除非其显式的调用了其close()方法将其连接关闭,否则是不会自动被GC 回收的。对于Resultset 和Statement 对象可以不进行显式回收,但Connection 一定要显式回收,因为Connection 在任何时候都无法自动回收,而Connection一旦回收,Resultset 和Statement 对象就会立即为NULL。但是如果使用连接池,情况就不一样了,除了要显式地关闭连接,还必须显式地关闭Resultset Statement 对象(关闭其中一个,另外一个也会关闭),否则就会造成大量的Statement 对象无法释放,从而引起内存泄漏。这种情况下一般都会在try里面去的连接,在finally里面释放连接。 7.5 内部类和外部模块等的引用 内部类的引用是比较容易遗忘的一种,而且一旦没释放可能导致一系列的后继类对象没有释放。此外程序员还要小心外部模块不经意的引用,例如程序员A 负责A 模块,调用了B 模块的一个方法如: public void registerMsg(Object b); 这种调用就要非常小心了,传入了一个对象,很可能模块B就保持了对该对象的引用,这时候就需要注意模块B 是否提供相应的操作去除引用。 7.6 单例模式 不正确使用单例模式是引起内存泄露的一个常见问题,单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄露

真正彻底释放、手机内存可用空间

手机需 .打开管理器,进入手机目录下,里面全是一些数据文件,不管软件安装在手机或内存卡,都会在这里生成文件,特别是当软件删除后,文件仍然留在此目录下.资料个人收集整理,勿做商业用途 .文件名全部为英文,大家仔细看文件名后看软件是否已经删除,删除了地就可以直接删除文件,每个文件占用空间都比较大,真正彻底释放手机内存可用空间.资料个人收集整理,勿做商业用途 .当然后删除自带地软件里面也是有残留文件地,对准软件名后可以一一删除,如果哪个文件名不知具体是哪个软件,多百度吧.资料个人收集整理,勿做商业用途 .打开管理器,进入手机目录下,里面是一些日志文件,占用地空间也是非常大地,可以全部删除,不过开机后仍然有两三个文件会自动生成,没关系.资料个人收集整理,勿做商业用途 深度清理三星安卓手机各种残留文件,释放手机内存可用空间”教程 、本教程由官方出品,适用所有三星安卓手机:~4.1.2,自己用了久,效果刚刚滴!论坛没人发,我给大家分享一下!资料个人收集整理,勿做商业用途 、深度清理三星安卓手机各种残留文件教程: 、首先,你得要,对于有系统洁癖滴你来说,眼里揉不进沙子呵呵,那是必须装文件浏览器地. 、进入浏览器,然后第二个文件就是了,进入后删除全部即可. 、返回浏览器主页,找到文件夹,进入后往下拉,找到文件夹,进入后删除全部即可,有时候你地手机会因为这样那样滴原因而资料个人收集整理,勿做商业用途 、产生系统错误,就会产生那个高达左右滴文件了. 、接下来,进入刺激滴环节,在浏览器主页面,找到文件夹,往下拉,找到文件夹,进入后你会看到诸多结尾滴文资料个人收集整理,勿做商业用途 、件,有些你通过名字即可判知其所属软件程序.那为啥要清理那些文件呢?因为在你安装软件、游戏后,就好在这个目录下产生文件,资料个人收集整理,勿做商业用途 、而删除软件后,它还存在地而且你可以借助文件浏览器看一下他们滴大小,呵呵,很惊人吧. 、那接下来就是点击最左下角滴虚拟功能键,点击“多选模式”,然后点“全部选择”,点击“删除”即可,接下来要赶紧做地事情就是资料个人收集整理,勿做商业用途 、退出浏览器,迅速关机,否则时间长了就会产生系统错误通知. 、开机后再去看看这些文件,是地,他们又自动生成了! 但是删除软件地那些文件就消失地无影无踪了,这样可以有效清理很多无资料个人收集整理,勿做商业用途 、用地废品,节省空间. 全面清理三星安卓手机各种残留文件教程 首先,你得要,对于有系统洁癖滴你来说,眼里揉不进沙子呵呵,那是必须装文件管理器地. 进入管理器,然后第二个文件就是了,进入后删除全部即可. 返回管理器主页,找到文件夹,进入后往下拉,找到文件夹,进入后删除全部即可,有时候你地手机会因为这样那样滴原因而资料个人收集整理,勿做商业用途 产生系统错误,就会产生那个高达左右滴文件了. 接下来,进入刺激滴环节,在管理器主页面,找到文件夹,往下拉,找到文件夹,进入后你会看到诸多结尾滴文资料个人收集整理,勿做商业用途 件,有些你通过名字即可判知其所属软件程序.那为啥要清理那些文件呢?因为在你安装软件、游戏后,就好在这个目录下产生文件,资料个人收集整理,勿做商业用途

apache服务器出现内存溢出的解决方法

apache服务器出现内存溢出的解决方法 2011-10-08 14:26 Tomcat内存溢出的原因 在生产环境中tomcat内存设置不好很容易出现内存溢出。造成内存溢出是不一样的,当然处理方式也不一样。 这里根据平时遇到的情况和相关资料进行一个总结。常见的一般会有下面三种情况: 1.OutOfMemoryError: Java heap space 2.OutOfMemoryError: PermGen space 3.OutOfMemoryError: unable to create new native thread. Tomcat内存溢出解决方案 对于前两种情况,在应用本身没有内存泄露的情况下可以用设置tomcat jvm参数来解决。(-Xms -Xmx -XX:PermSize -XX:MaxPermSize) 最后一种可能需要调整操作系统和tomcat jvm参数同时调整才能达到目的。 第一种:是堆溢出。 原因分析: JVM堆的设置是指java程序运行过程中JVM可以调配使用的内存空间的设置.JVM在启动的时候会自动设置Heap size的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置。Heap size 的大小是Young Generation 和Tenured Generaion 之和。 在JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息。 Heap Size 最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。 没有内存泄露的情况下,调整-Xms -Xmx参数可以解决。 -Xms:初始堆大小 -Xmx:最大堆大小 但堆的大小受下面三方面影响:

一次内存泄露问题的排查

一次内存泄露问题的排查 系统对外提供的Solr查询接口,在来自外部调用的压力加大之后,就会出现solr查询报Read Timed Out的异常,从表面现象上看是此时solr核压力过大,无法响应过多的查询请求。 但实际上此时并发查询压力并不是很大,那么为何solr核会无法及时响应查询请求呢?首先用top查看了下load average,也是很低,也佐证了系统本身压力并不大。 然后,用jstack –l 查看那些cpu使用率过高的线程,发现全都是GC线程,说明GC过于频繁,而且耗时过长,导致应用线程被挂起,无法响应客户端发来的请求,这种情况就应该是有存在内存泄露的问题咯。

于是,就用jmap将进程的堆转储文件dump出来到heap.bin文件中JMap -dump:format=b,file=/tmp/heap.bin 然后用Eclipse Memory Analyzer(MAT)打开堆转储文件进行分析通常我们都会采用下面的“三步曲”来分析内存泄露问题: 首先,对问题发生时刻的系统内存状态获取一个整体印象。 第二步,找到最有可能导致内存泄露的元凶,通常也就是消耗内存最多的对象

接下来,进一步去查看这个内存消耗大户的具体情况,看看是否有什么异常的行为。 下面将用一个基本的例子来展示如何采用“三步曲”来查看生产的分析报告。 如上图所示,在报告上最醒目的就是一张简洁明了的饼图,从图上我们可以清晰地看到一个可疑对象消耗了系统75% 的内存。 现在,让我们开始真正的寻找内存泄露之旅,点击“Leak Suspects”链接,可以看到如下图所示对可疑对象的详细分析报告。

c语言中动态内存申请与释放的简单理解

c语言中动态内存申请与释放的简单理解 在C里,内存管理是通过专门的函数来实现的。与c++不同,在c++中是通过new、delete函数动态申请、释放内存的。 1、分配内存 malloc 函数 需要包含头文件: #include 或 #include 函数声明(函数原型): void *malloc(int size); 说明:malloc 向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。 从函数声明上可以看出。malloc 和 new 至少有两个不同: new 返回指定类型的指针,并且可以自动计算所需要大小。比如: int *p; p = new int; //返回类型为int* 类型(整数型指针),分配大小为 sizeof(int); 或: int* parr; parr = new int [100]; //返回类型为 int* 类型(整数型指针),分配大小为sizeof(int) * 100; 而 malloc 则必须由我们计算需要的字节数,并且在返回后强行转换为实际类型的指针。 int* p; p = (int *) malloc (sizeof(int)); 第一、malloc 函数返回的是 void * 类型,如果你写成:p = malloc (sizeof(int)); 则程序无法通过编译,报错:“不能将 void* 赋值给 int * 类型变量”。所以必须通过 (int *) 来将强制转换。 第二、函数的实参为 sizeof(int) ,用于指明一个整型数据需要的大小。如果你写成:

Office2016 Excel的VBA打开显示内存溢出解决办法

Office2016 Excel的VBA打开显示内存溢出解决办法 1、在excel开发工具中打开查看代码显示内存溢出 刚安装完office2016,但是Excel中的Visual Basic却不能用。原因是 加载路径有问题,以前装了WPS软件,加载路径在WPS文件夹里面。都是WPS 搞的鬼,解决办法是,通过修改注册表的键值到VBE6EXT.OLB所在目录即可。2、解决方法 打开注册表:HKEY_CLASSES_ROOT\TypeLib{0002E157-0000-0000-C000-000000000046}\5.3\0\win32,我右侧数据显示加载路径是 “C:\Users\Administrator\AppData\Local\Kingsoft\WPS Office\10.1.0.5554\office6\vbe6ext.olb”将之修改为你VBE6EXT.OLB文件路径,我的是“C:\Program Files\Common Files\Microsoft Shared\VBA\VBA6\VBE6EXT.OLB”(不知道在哪儿话,直接搜索就好了,VBA6不记得是否是我自己加的了,反正路径下有这个文件,在哪都一样。该方法实测有效) 3.其他方法 (1)卸载重装 点评:这个办法有时候管用,有时候也不管用,视具体情况而定,但个人不建议采用,因为这样的永远都让你学不到东西。 (2)移动VBE6EXT.OLB文件到C:\Program Files\Common Files\microsoft shared\VBA\VBA7 点评:“VBE6EXT.OLB”“VBA7”这两个文件在哪,一搜索便知,据说解决了部分的问题,但有的人电脑里没有VBA7这个文件夹,就无从下手了,亲测新建一个VBA7文件夹貌似也不可以,并非通用方法。

内存溢出和内存泄漏的区别

内存溢出和内存泄漏的区别(内存泄漏原因) 内存溢出out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。 内存泄露memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。 memory leak会最终会导致out of memory! 内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。 内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出!比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出. 以发生的方式来分类,内存泄漏可以分为4类: 1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。 2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。 3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。 4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。 从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。

C语言内存泄漏原因及对策分析

C语言中的内存泄漏原因及对策分析 引言: 在C语言程序设计中,内存泄漏几乎是很难避免的,C程序产生泄漏内存,则运行速度会逐渐变慢,并最终停止运行;如果产生覆盖内存,程序会变得非常脆弱,很容易受到恶意用户的攻击。内存泄漏是一种隐性危害,它们很难被发现,通常不能在相应的源代码中找到错误,需要仔细分析与专门的检测工具才能发现。 1、内存泄漏的定义 通常我们所说的内存泄漏,是指分配出去的内存在使用之后没有释放掉,没有回收,长此以往,会造成没有足够的内存可以分配。一般表现为运行时间越长,占用的内存越多,最终导致系统奔溃。 一般的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显式释放的内存。应用程序一般使用malloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free 或delete释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。 2、内存泄漏原因分析 内存泄漏的原因实质是没有释放向系统申请的内存,要了解内存泄漏产生的原因,我们首先了解C语言内存分配情况。 2.1 C语言内存分配情况 在C语言中,根据数据在内存中存在的时间(生存周期)不同,

将内存空间分为三个区: 1)程序区:用于存储程序的代码,即程序的二进制代码。 2)静态存储区:用于存储全局变量和静态变量,这些变量的空间在程序编译时就已经分配好了。 3)动态存储区:用于在程序执行时分配的内存,又分为:堆区(heap)和栈区(stack)。堆区:用于动态内存分配,程序运行时由内存分配函数在堆上分配内存。在C语言中,只能使用指针才能动态的分配内存。栈区:在函数执行时,函数内部的局部变量和函数参数的存储单元的内存区域,函数运行结束时,这些内存区域会自动释放。 2.2 C语言动态内存分配 在C语言中用内存分配函数来实现内存的动态分配,这些函数有:malloc()和realloc()等函数。malloc(): 使用这个函数时需要包含头文件。使用该函数需要指定要分配的内存字节数作为参数,例如: int *pNumber=(int *) malloc(100) 这条语句分配了100个字节的内存,并把这个内存块的地址赋给pNumber,这个内存块可以保存最大25个int值,每个int占4个字节。如果不能分配请求的内存,malloc()会返回一个null指针。 2.3 释放动态分配的内存 堆上分配的内存会在整个应用程序结束之后,由操作系统负责回收,但最好是在使用完这些内存后立即释放。如果不释放,会引起内存泄漏,极大占用系统资源,可能会产生各种未知的错误。所以,必

Java内存泄露模拟及分析解决方法

derwee Java内存泄露模拟及分析解决方法 1.1 实践目标: 1、使用JA V A代码实现模拟内存溢出 2、分析JDK内存溢出的原因 3、总结存在bug的JA V A编码实践 4、总结JVM优化的方法 1.2 模拟内存溢出: 为了方便模拟内存,特意把JVM的内存参数指定为更小(我的本本内存是8G的)。修改eclipse参数文件调用JVM参数: -vmargs -Xms40m(原始是-Xms40m) -Xmx100m(原始是-Xmx384m) 演示JA V A小程序实现原理:使用集合类对象装载大量的Persion对象,每次把new出来的对象加入集合类对象后,更改对象的属性,再从集合类对象中删除该对象。会出现该删除的对象没有被删掉,Persion类对象不断占用内存,导致分配给JVM的内存被耗光。 package .*; /** * * @ClassName: OutOfMemory * @Description: 内存溢出模拟,提出解决方法 * @author yangdw * @date 2012-3-25 下午6:58:49 */ public class OutOfMemory { public static void main(String[] args) { Collection collection = new HashSet(); for(int i=0;i<0;i++) { Persion per = new Persion(i,"yangdw"); (per);

1.2.1equals和hashcode重写原则[2] 1.2.1.1 对equals()应该遵循如下要求 1)对称性:如果(y)返回是“true”,那么(x)也应该返回是“true”。 2)自反性:(x)必须返回是“true”。 3)传递性:如果(y)返回是“true”,而且(z)返回是“true”,那么(x)也应该 返回是“true”。 4)任何情况下,(null),永远返回是“false”。 5)(和x不同类型的对象)永远返回是“false”。 1.2.1.2 hashCode()的返回值和equals()的关系如下 1)如果(y)返回“true”,那么x和y的hashCode()必须相等。 2)如果(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不 等。

相关主题