锁定老帖子 主题:项目事故和安全语言
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2006-09-27
robbin 写道 同样的配置以前也从来没有出过问题,只不过以前是32bit cpu,32bit 操作系统,但是这次是AMD CPU,Linux x86_64操作系统,用PHP4就出问题了,但是ruby没有问题。因此我怀疑是PHP4自己代码在64位操作系统上面有内存泄漏的bug。
很不好意思地再问下去, ,用的Linux内核是哪个版本?先后试过的两个Linux distribution是哪两个? Apache是哪个版本? |
|
返回顶楼 | |
发表时间:2006-09-27
bigpanda 写道 robbin 写道 同样的配置以前也从来没有出过问题,只不过以前是32bit cpu,32bit 操作系统,但是这次是AMD CPU,Linux x86_64操作系统,用PHP4就出问题了,但是ruby没有问题。因此我怀疑是PHP4自己代码在64位操作系统上面有内存泄漏的bug。
很不好意思地再问下去, ,用的Linux内核是哪个版本?先后试过的两个Linux distribution是哪两个? Apache是哪个版本? CentOS4.3, SLES9 SP3 (x86_64 bit,都update到最新的patch了) kernel-2.6.5-xxx Apache2.2, Apache2.0, lighttpd-1.4.11 PHP4.4.0, PHP4.4.4 以上版本的各种组合都试过了,内存泄漏依旧,不同的组合泄漏速度有所不同,把PHP换成ruby,一切恢复正常。 在这里我很想澄清一个概念:memory leak(内存泄漏)。 按照上面各位的说法,只要kernel内存管理没有问题,不论用户进程的内存管理多么烂,只要用户进程被杀,所有引用的内存都会被释放掉,对吧?这是上面各位讨论的一个结论。我还没有找到明确证据反驳这种说法,但是按照这种说法的话,所谓memory leak(内存泄漏)这个说法就根本不存在!因为用户进程使用的内存永远不会失控,也就是说就算用户进程使用的内存超过了物理内存,但是只要用户进程关闭,再多的内存也全部都会被释放回来。这种情况根本就不叫内存泄漏,顶多叫做out of memory。 其实说java程序内存泄漏,这种说法也是错误的,只要JVM没有问题,java程序写的再烂,内存也不会泄漏,最多就是GC无法去回收而已,导致JVM的堆内存越用越多,这不叫leak,叫做out of memory。 我碰到的这种情况是确确实实的内存泄漏,而且我很有把握的认为Kernel没有问题。因为推荐我使用SuSE9 SP3 x86_64的Unix专家已经在无数大型系统,甚至一些你们想像不到的巨大负载的系统上面部署和稳定运行这个版本的kernel了。 再说一个现象,根据我当时对memory leak的观察,用户进程使用的resident内存并没有增加很稳定,系统buffer,disk cache也没有增加很稳定,但是用户进程持续不断向kernel申请更多的内存,却从来没有向kernel回吐内存。这就好像一个人拼命喝酒,但是他的肚子就像一个无底洞那种感觉。 如果我观察到了内存回吐现象,但是最终内存不够,我可以认为是kernel问题,但是用户进程哪怕从来都没有回吐内存,同时自己占用resident去从来不增加,就像一个无底洞,一点一点的吃内存。 |
|
返回顶楼 | |
发表时间:2006-09-28
程序的内存泄漏和执行程序的进程在关闭后其内存被释放是两件事情
前者是应用程序开发者干的事情,后者是操作系统编写者干的事情,有的操作系统会在进程killed之后释放进程的内存,有的不会,有的貌似会但是因为系统bug而实际上没有... 只不过在那些不会在进程关闭后释放内存的系统中,应用程序的内存泄漏会导致更加严重的问题。而在那些会释放关闭后进程的内存的系统中,内存泄漏的问题主要存在于那些长期运行的服务类程序,这类程序通常不会被频繁关闭,泄漏的堆积会导致内存管理子系统频繁的在物理内存和硬盘间倒腾数据(术语叫'颠簸'?) |
|
返回顶楼 | |
发表时间:2006-09-28
我今天有点感冒了,头昏昏沉沉,写完这篇睡觉去。
我也无法解释Robbin的机子为什么会出现那种情况,如果有人Linux功力够,可以架起Kernel Debugger, 一直追踪到底。当然得有时间,还得配置一样的机子。我的Linux功力实在不够,无法再探讨下去了。平时也就用用Windows,刚刚开始用FreeBSD。Windows Kernel Debugger还架设的起来,Linux内核跟踪就无能为力。 关于操作系统释放内存的事再说两句。操作系统在创建进程的时候会给那个用户进程生成一个4G的虚拟进程专用空间,用户进程自己代码只能直接读写操作这虚拟4G内存。进程结束(不管是自己结束还是被强制结束)时,操作系统把这4G的虚拟进程收回去。所有现代主流操作系统,Windows NT/2k/XP/2003/Vista, Linux, BSD, Mac OS X都是如此。为了求证,我翻了四本书: The Design and Implementation of the 4.4 BSD Operating System, Operating Systems concepts and design,2nd edition The Logical Design of Operating Systems,2nd edition Operating System Concepts, 5th edition 里面都是这么说的,还不算我以前引的Jeffrey Richter的那本,这几本书都在我案头上,够权威态度够严谨了吧。还怀疑的话推荐学习Minix操作系统,Operating Systems: design and implementation一书非常好。 前面有人扯到linux会对进程打开过的文件做cache,用以证明进程在退出之后,占用的内存仍然没有释放。 这完全是两码事。文件系统cache又不在这4G的虚拟进程专用空间里。文件系统是内核的一部分,自己对最近用的文件cache一下是为了优化。(windows的NTFS一样会cache) 用户进程在x86上只能在Ring 3级别跑,想读写文件或访问网络只能通过System Call来做. 这些System Call(Linux里面有200来个),可都是在Ring 0级别跑的,在Ring 0里面那可是个自由的天地,什么进程,内存保护的限制都没有,代码爱干什么干什么。 不是所有在Ring 0里跑的代码,都是Linux内核团队写的。IO的驱动程序都是在内核跑的,但不少是别人写的。这些代码要是遗漏内存,系统会崩溃。 内存遗漏和OutOfMemory还是两码事。一段代码,成功的申请了1k的内存,然后没有释放,这段代码遗漏内存,但是内存申请成功了。一段代码,向系统申请内存,系统无法分配内存,这才是OutOfMemory。我以前用Java写过一个Web Application,在Tomcat下跑,里面file upload的码是自己写的,在内存里生成个同样大的ByteArray,没有检查文件大小,结果有个人上载300MB的文件,JVM申请那么大的内存块失败,在Jsp页上直接打出了Stack Trace.但是Tomcat还是跑的好好的,操作系统(Linux)还是跑的好好的.那个 JVM占用的内存高达1.7G,好好的又跑了一个月,直到系统更新。 但是我写一个小小的程序,里面要有个函数遗漏内存,如果这个函数只呼叫一次,那么一点不影响使用。但是在VC debug下调试,退出时debugger还是会告诉你内存遗漏. OutOfMemory,可能是程序内存遗漏而产生的恶果,但也可能不是,就像我写的那个苯苯的程序,虽然OutOfMemory,但不遗漏内存。 内存遗漏的代码,如果是小程序偶尔跑一次,影响不大,如果是服务器天天跑,倒最后也就会屡屡申请内存,操作系统不停的说No,别的事就耽误了,如果是跑在Ring 0里,最终会Kernel Panic。所以内存泄漏还是存在的,在不同的地方后果不一样。 robbin 写道 因为推荐我使用SuSE9 SP3 x86_64的Unix专家已经在无数大型系统,甚至一些你们想像不到的巨大负载的系统上面部署和稳定运行这个版本的kernel了。
我一点不否认Linux的负载能力和稳定性,但是这不能证明那台机子上在内核里跑的代码(包括Linux内核及第三方驱动程序),全部没有错。Linux内核的代码if,else,for嵌套一大堆,没准在那台机子特定的条件下,激活的代码就有Bug。 Linux的netfilter,可是在Ring 0里面跑的,看看这个帖子,Linux Kernel Team的人是怎么说的: Re: [PATCH] fix mem-leak in netfilter 这个源代码可以在这里找到:http://www.promethos.org/lxr/http/source/net/ipv4/netfilter/ipt_recent.c 看里面逻辑套的,得算是bad smell了吧。 robbin 写道 再说一个现象,根据我当时对memory leak的观察,用户进程使用的resident内存并没有增加很稳定,系统buffer,disk cache也没有增加很稳定,但是用户进程持续不断向kernel申请更多的内存,却从来没有向kernel回吐内存。这就好像一个人拼命喝酒,但是他的肚子就像一个无底洞那种感觉。
用户进程向kernel申请更多的内存,如果申请成功了,使用的resident内存却没有很稳定增加,这是不是很矛盾啊。 用户进程想读写文件或访问网络只能通过System Call,内核里面的代码会跑一圈,这里面要是内存遗漏外面是看不出来的。 要想再追根问底,我看只能搭个kernel debugger追踪一下。不然就成悬案了,就像我们现在也不知道肯尼迪是谁杀的。 |
|
返回顶楼 | |
发表时间:2006-09-28
>但是按照这种说法的话,所谓memory leak(内存泄漏)这个说法就根本不存在!
这个说法可以存在,内核可以内存泄露。 >用户进程持续不断向kernel申请更多的内存 我必须确认你说的“向kernel申请更多的内存”是什么意思,申请的是内核态的内存,还是申请的是用户态的内存,如果是用户态的内存,是在数据段以内申请内存,还是要在数据段以外申请内存。 |
|
返回顶楼 | |
发表时间:2006-09-28
jack 写道 有个从表面上看起来很奇怪的事实是:司机戴安全带比不带安全带时发生的行车事故要多。不带安全带时,司机死亡率比较高,但是带了安全带时,司机死亡率是降低了,但是行人死亡率却提高了。
不带安全带时,司机需要谨慎缓慢的开车,带了安全带,司机却会 更快,更放肆地开车。 这个方面的资料 可以看下 Automobile Safety Regulation and the Incentive to Drive Recklessly:Evidence from NASCAR 和Automobile Safety Regulation 我觉得这个的原因是因为戴安全带的司机比不带安全带的司机多得多吧。。 |
|
返回顶楼 | |
发表时间:2006-09-28
ddd 写道 >但是按照这种说法的话,所谓memory leak(内存泄漏)这个说法就根本不存在!
这个说法可以存在,内核可以内存泄露。 >用户进程持续不断向kernel申请更多的内存 我必须确认你说的“向kernel申请更多的内存”是什么意思,申请的是内核态的内存,还是申请的是用户态的内存,如果是用户态的内存,是在数据段以内申请内存,还是要在数据段以外申请内存。 用户态内存。数据段以内申请内存。 我为什么不怀疑Kernel,也是因为SLES自己也带PHP的,如果kernel有这方面问题,早被发现出来了。只不过我用的不是默认的,是我自己下载源代码编译的。而PHP向来安全性就做的不好。 |
|
返回顶楼 | |
发表时间:2006-09-28
>用户态内存。数据段以内申请内存
这样的内存申请不经过内核,如果是c程序,是库函数完成的,直接对数据段中的堆区域进行操作。 当然如果需要映射的话是要经过内核的。 |
|
返回顶楼 | |
发表时间:2006-09-28
这种问题过去在32位操作系统从未遇到过,我一直怀疑64位操作系统的内存管理方式有所不同,而PHP不兼容这种方式造成的。
|
|
返回顶楼 | |
发表时间:2006-09-28
[quote="robbin]
在这里我很想澄清一个概念:memory leak(内存泄漏)。 ....也就是说就算用户进程使用的内存超过了物理内存,但是只要用户进程关闭,再多的内存也全部都会被释放回来。这种情况根本就不叫内存泄漏,顶多叫做out of memory。 其实说java程序内存泄漏,这种说法也是错误的,只要JVM没有问题,java程序写的再烂,内存也不会泄漏,最多就是GC无法去回收而已,导致JVM的堆内存越用越多,这不叫leak,叫做out of memory。 ..... 再说一个现象,根据我当时对memory leak的观察,用户进程使用的resident内存并没有增加很稳定,系统buffer,disk cache也没有增加很稳定,但是用户进程持续不断向kernel申请更多的内存,却从来没有向kernel回吐内存。这就好像一个人拼命喝酒,但是他的肚子就像一个无底洞那种感觉。 robbin概念上似乎还有问题。 memory leak 是对系统而言的,out of memory是对进程而言的,而且是和virtual memory 有关,不是 物理内存。 或者说两者角不同,可能准确 "Out of memory (OOM) is a pathological state of computer operation where all available virtual memory has been allocated" "In computer science, a memory leak is a particular kind of unintentional memory consumption by a computer program where the program fails to release memory when no longer needed." 你所说的 "用户进程持续不断向kernel申请更多的内存", 你不说kill 掉了吗? 给你两个连接: http://en.wikipedia.org/wiki/Out_of_memory http://en.wikipedia.org/wiki/Memory_leak |
|
返回顶楼 | |