导航:
论坛 -> DELPHI技术
斑竹:liumazi,sephil
作者:
jingzu (123456)
★☆☆☆☆
-
盒子活跃会员
2023/11/14 8:23:31
标题:
用什么方法检查出现 "Out of memory"引起崩馈问题?
浏览:674
加入我的收藏
楼主:
我的DELPHI 程序,在运行24小时左右,就会出现"Out of memory"引起崩馈。 用了 fastmm4,fastmm5,madExcept等都没有办法检测出来 请问各位大侠,用什么方法检测这个问题?
----------------------------------------------
永远是DELPHI初学者。
作者:
2023/11/14 8:52:18
1楼:
要用鈔能力,鈔票夠多,就會有人幫你忙的了。
----------------------------------------------
-
作者:
abencat (远离delphi的人)
★☆☆☆☆
-
盒子活跃会员
2023/11/14 8:56:25
2楼:
写日志文件 排查
----------------------------------------------
delphi爱好者
作者:
2023/11/14 9:08:35
3楼:
应该是内存泄漏,如果工具无法找到,就是仔细检查源代码!
----------------------------------------------
-
作者:
2023/11/14 9:16:38
4楼:
也遇到一样的问题,排查是FireDAC查询数据库有泄露(循环查询线程),目前还没找到症结
----------------------------------------------
-
作者:
2023/11/14 9:22:02
5楼:
Out of memory不一定是泄露。 我理解的是,泄露是指你的程序退出了,一些该管理的内存没跟着释放。 如果out of memory了,也有可能是你的程序存在某处一直在申请新的内存空间。
----------------------------------------------
z@S7
作者:
2023/11/14 9:53:35
6楼:
它不是退出吧, 是线程循环出问题了. 你可以试试一个一个关闭线程, 看问题还会不会重现, 就知道哪个线程方法出问题了, 再一行一行注释, 找出哪一行有问题.
----------------------------------------------
delphi界写python最强, python界写delphi最强. 写自己的代码, 让别人去运行.
作者:
2023/11/14 10:29:39
7楼:
FDQuery查询完FreeAndNil后,有时有内存没释放情况(有时又释放了),导致程序占用内存慢慢增加最后“out of memory”、“资源不足”等异常 逐行跟踪调试FireDAC.Comp.DataSet、Data.DB等单元没能发现异常,可能水平有限,希望大神看能否遇到及解决:),目前只能用每天自动重启来顶一下
----------------------------------------------
-
作者:
2023/11/14 11:20:22
8楼:
估计内存泄露。你在调试中,单线程模式下不被触发,放到服务端,多线程下,触发错误。如果是后台,建议捕捉异常写出日志。精确到哪一个过程或函数。我的常用处理日志方法是 WriteLog('过程名:' + e.message);不至于自己读日志时莫名其妙。
----------------------------------------------
-
作者:
2023/11/14 11:48:10
9楼:
方法一: 设置ReportMemoryLeaksOnShutDown := True; 看看程序关闭时有没有报内存泄漏, 有的话分析一下那些内存泄漏信息. 方法二 用排除法来定位错误原因, 把可疑的部分不让它运行,看看还有没有内存泄漏,这样一个一个的试,最终找出内存泄漏的原因并不难.
----------------------------------------------
-
作者:
2023/11/14 12:11:29
10楼:
感谢楼上兄弟 方法一、方法二有用过 是一个奇怪问题,FastMM没有检测到内存泄露,排除定位就是open多次查询后内存增加 网上大神们的内存获取和清理方法: function GetAllocatedMemoryBytes : Int64; // Get the size of all allocations from the memory manager var MemoryManagerState: TMemoryManagerState; SmallBlockState: TSmallBlockTypeState; i: Integer; begin GetMemoryManagerState( MemoryManagerState ); Result := 0; for i := low(MemoryManagerState.SmallBlockTypeStates) to high(MemoryManagerState.SmallBlockTypeStates) do begin SmallBlockState := MemoryManagerState.SmallBlockTypeStates[i]; Inc(Result,SmallBlockState.AllocatedBlockCount*SmallBlockState.UseableBlockSize); end; Inc(Result, MemoryManagerState.TotalAllocatedMediumBlockSize); Inc(Result, MemoryManagerState.TotalAllocatedLargeBlockSize); end; //清理内存 (任务管理器上程序内存能清理,实际解决不了,还是out of memory) function ClearMemory:Boolean; begin Result:= False; try if Win32Platform = VER_PLATFORM_WIN32_NT then begin SetProcessWorkingSetSize(GetCurrentProcess, $FFFFFFFF, $FFFFFFFF); end; Result:= True; except end; end;
----------------------------------------------
-
作者:
bdl1 (bdl1)
▲▲▲▲▲
-
普通会员
2023/11/14 16:09:31
11楼:
有一个办法,换有uniDAC试下,看还是这不是这样?
----------------------------------------------
-我的博客
作者:
2023/11/14 18:01:10
12楼:
首先你要确定是 FireDAC 带来的内存泄露,还是你自己的代码带来的。 这个好办,写个循环,拼命打开关闭 FdQuery 一万次,十万次,看看你的程序占用内存有没有一直在增加。 如果确认 FireDAC 没有问题。那么,进一步,看看你自己的代码,哪里使用了内存没有释放的。 最简单的可能就是你创建了一个对象,没有释放,然后循环使用这个,那就是没有释放的对象越来越多..........当然最后就内存不够了。 除了创建对象,你还有没有其它的分配内存的代码?都需要仔细检查。 另外,如果是服务器端,需要长期稳定工作,又怕内存泄漏,那就学 Oracle 的做法,服务器端接受一个客户端的连接就创建一个进程,客户端断开连接消灭进程。再有内存泄漏的程序,进程都消灭了,泄漏的内存也就被 OS 自动回收了。这样保证稳定。这也是 Oracle 数据库当年号称极其稳定的法宝。 再举个例子,FireBird 数据库,安装的时候,有两种模式:1. Classic;2. Super; Classic 模式就是独立进程服务一个客户端,有 N 个客户端,它就启动 N 个进程。效率是低一点(独立的进程占用的内存更多,启动进程也需要更多 CPU 时间),但是稳定。 Super 模式就是服务内部用多线程,N 个客户端连接,服务器端就用 N 个线程去处理。这样的好处是效率更高。但是,如果服务器端(也就是数据库本身)有 bug 导致的内存泄漏,那 N 个客户端反复连接后,可能它的内存占用就会越来越多了。 总之,用 Delphi 写程序,只要注意自己的代码,哪里创建,哪里回收,就不怕有内存泄漏发生。当然,如果是别人的代码库(比如 FireDAC 或者其它第三方的控件)有问题,那就不好搞了。首先还是保证自己的代码没问题吧。
----------------------------------------------
-
作者:
jingzu (123456)
★☆☆☆☆
-
盒子活跃会员
2023/11/14 18:35:28
13楼:
现在不清楚,有时运行72小时出现,有时运行48小时出现,有时运行24出现,所以时间不定,很难查,查出现时,内存并不大,大约70M左右。基本在20-70M间变动。 是32位程序。当出现"Out of memory"时,程序必然崩馈。
----------------------------------------------
永远是DELPHI初学者。
作者:
2023/11/14 19:53:58
14楼:
通常来说Out of memory 触发同时用了fastmm+内存泄漏检测dll 就能找到基本问题点。
----------------------------------------------
[alias] co = clone --recurse-submodules up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/ >http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/
作者:
2023/11/14 22:26:27
16楼:
我觉得delphi的string 本身估计有问题。 最好设置string 变量是改成 var s:string[100];
----------------------------------------------
123
作者:
2023/11/14 22:43:21
17楼:
string 是没有问题的。这一点我敢肯定。 不要老去怀疑 Delphi,一般这种情况都是自己的代码的问题。 13楼说有时72小时出问题有时48小时出问题时间不定所以很难查,这个说法是错误的。这个和时间没关系,和某个功能的运行次数有关系。如果跑了 100 个小时,那个有问题的功能只运行了3 次,估计也不会出问题。 所以,很简单,把那些反复运行的功能,加上 log,运行一次计数一次,就知道运行多少次出问题了。 这种情况,一多半是某个功能有内存泄漏,然后那个功能被反复调用了 N 多次,累积起来,最后出问题。 写 Delphi 的程序,要做到没有内存泄漏,其实也简单。比如,不要做内存分配/指针操作这样的代码(容易犯错),而尽量用对象的方式。 然后,对象的创建和释放,尽量在代码里面采用不会漏写释放代码的代码风格。实在有些代码无法保证对象一定会被释放 -- 在这里创建的对象,在其它地方使用,代码无法保证它被释放的时机,那这种对象,你采用接口的方式,调用它的接口,就利用了 Delphi 的一个机制:接口没有引用的时候,对象会被自动释放。使用了这个机制,就能保证没有对象没释放导致的内存泄漏了。
----------------------------------------------
-
作者:
2023/11/14 22:55:33
18楼:
String 是唯一manage 的型別。 這東西跟JAVA 的STRING 一樣,你亂用一樣會死。
----------------------------------------------
-
作者:
kwer (★★★★★)
★☆☆☆☆
-
普通会员
2023/11/15 8:05:03
19楼:
我同意16楼,,,string 是有界的,,,还有一个就是List也容易出现越界错误。
----------------------------------------------
==========-==========-==========-==========-========== 多隆, 给我备一匹最快的马, 我有事要走先~~~ ==========-==========-==========-==========-==========
作者:
2023/11/15 12:12:28
20楼:
看看是不是你的Delphi版本太旧了, 换一个Delphi 10以上的新版本试试
----------------------------------------------
-
作者:
2023/11/15 17:41:16
21楼:
用用你的智慧,找找特点,自然就解决了。
----------------------------------------------
软件是什么,相信很多人都说不清。
作者:
2023/11/15 23:58:30
22楼:
之前出现过这个情况,也是16楼说的那样去设置String[100],之后客户再没有出现这个情况。
----------------------------------------------
-
作者:
2023/11/16 8:42:41
23楼:
var s:string[100]; 的意義是什麼?
----------------------------------------------
-
作者:
2023/11/16 9:37:13
24楼:
s:string[100]和s:String的区别 类似于 buf:array[0..99] of byte和buf:array of byte的区别 类型ShortString的定义是: type ShortString = string[255]; Sizeof(ShortString) == 256
----------------------------------------------
-
作者:
2023/11/16 10:03:04
25楼:
哪再問,怎麼不用byte array with fixed length 就好。 非得要改用string 呢?因為兩個都有out of boundary 的問題。
----------------------------------------------
-
作者:
2023/11/17 10:11:50
26楼:
内存泄漏的查找确实比较困难,尤其是服务器端,通过写日志来定位是个很好的方法,可通过检查自己的代码特别是类的创建与销毁、函数调用中途退出等可能越过释放被创建的对象的代码以及反复创建、销毁等操作,还有大块内存申请操作、多线程的内存申请与释放等...,仔细检查自己的代码应该可以找到问题所在。
----------------------------------------------
==========
作者:
2023/11/17 10:50:39
27楼:
1. 可能是你的程序同一时间很多线程在跑着,然后每一个线程都用了很多的内存,超出32bits的可用内存就会Out of memory。 2. 可能是你的程序跑完线程后没有马上释放内存,导致内存用完了就会Out of memory。 试试用64 bits或者跑完线程后马上释放内存。
----------------------------------------------
-
作者:
2023/11/17 13:10:41
27楼:
string[100] 如果是全局变量,则会在编译时候写入 data 段,在代码中表现为绝对地址引用;如果是局部变量,则内存由编译器的栈框架进行维护,就是说字符串占用的内存全部都在栈中;但无论哪种变量,此数据占用内存长度(可能在堆也可能在栈)都不可修改,所以只要不越界,增加和删除字符串中的数据不涉及重分配内存的问题,所以执行较快。string 是由编译器维护的可变长度字符串,无论是哪种变量类型,都是只保存了一个指针指向其实际存储位置;所以增加数据,删除数据都可能涉及到内存的重分配,大字符串复制的时候消耗较多 CPU资源和 DMA 等等;不过都是由编译器自动添加编码,对程序员不可见;但是其好处就是长度不固定,操作起来容易,动态数组也是一样的规则;不过只要不跨模块(exe、dll),基本上不必操心其释放问题;除非你修改了它的引用域。 out of memory 的成因从系统层面看:32 位进程只能使用整个 4G 空间下部的 2G 地址空间(绝大多数情况,当然可以通过设置允许进程空间为 3G),而此时的状态是程序已经使用光了全部 2G 空间后继续请求分配内存(HeapAlloc),但系统已经无法再给程序提供,所以此 API 返回错误。如果此时没有发生内存访问冲突,则表示整个系统没有飞指针,但是其中很多内存块已经失去控制了。 对此情况没啥好的办法,从基本面来说,要清楚每种数据结构的分配机制,我们不就是通过数据结构来与编译系统打交道么?所以编译系统会如何对待我们所写下的数据结构一定要搞清楚:是分配在堆上还是在栈上,是编译器自动管理(delphi下只有string,包括ansistring、unicodestring、utf8string等等和动态数组)还是需要手动操作。另外就是系统 API 理解是否有误(仔细看MSDN中么个 API 对其参数的说明)以及其他 dll 对内存的管理是否正常。等等
----------------------------------------------
-
作者:
2023/11/17 13:13:32
28楼:
补充一下:64 位应用中,由于其内存地址大到基本上不必操心,所以这种情况很少见,除非分页文件也被用完才可能发生。但是由于程序不停分配内存又不复用,则会拖慢系统效率,导致系统假死;所以说 64 位下顶多可以延缓此问题发生,但不是解决之道,还是要查出问题所在修复才是。
----------------------------------------------
-