我今天有点感冒了,头昏昏沉沉,写完这篇睡觉去。
我也无法解释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。所以内存泄漏还是存在的,在不同的地方后果不一样。
[quote="robbin"]因为推荐我使用SuSE9 SP3 x86_64的Unix专家已经在无数大型系统,甚至一些你们想像不到的巨大负载的系统上面部署和稳定运行这个版本的kernel了。[/quote]
我一点不否认Linux的负载能力和稳定性,但是这不能证明那台机子上在内核里跑的代码(包括Linux内核及第三方驱动程序),全部没有错。Linux内核的代码if,else,for嵌套一大堆,没准在那台机子特定的条件下,激活的代码就有Bug。
Linux的netfilter,可是在Ring 0里面跑的,看看这个帖子,Linux Kernel Team的人是怎么说的:
[url=http://www.uwsg.iu.edu/hypermail/linux/kernel/0605.1/0008.html]Re: [PATCH] fix mem-leak in netfilter[/url]
这个源代码可以在这里找到:[url=http://www.promethos.org/lxr/http/source/net/ipv4/netfilter/ipt_recent.c]http://www.promethos.org/lxr/http/source/net/ipv4/netfilter/ipt_recent.c[/url]
看里面逻辑套的,得算是bad smell了吧。
[quote="robbin"]再说一个现象,根据我当时对memory leak的观察,用户进程使用的resident内存并没有增加很稳定,系统buffer,disk cache也没有增加很稳定,但是用户进程持续不断向kernel申请更多的内存,却从来没有向kernel回吐内存。这就好像一个人拼命喝酒,但是他的肚子就像一个无底洞那种感觉。[/quote]
用户进程向kernel申请更多的内存,如果申请成功了,使用的resident内存却没有很稳定增加,这是不是很矛盾啊。
用户进程想读写文件或访问网络只能通过System Call,内核里面的代码会跑一圈,这里面要是内存遗漏外面是看不出来的。
要想再追根问底,我看只能搭个kernel debugger追踪一下。不然就成悬案了,就像我们现在也不知道肯尼迪是谁杀的。
我也无法解释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。所以内存泄漏还是存在的,在不同的地方后果不一样。
[quote="robbin"]因为推荐我使用SuSE9 SP3 x86_64的Unix专家已经在无数大型系统,甚至一些你们想像不到的巨大负载的系统上面部署和稳定运行这个版本的kernel了。[/quote]
我一点不否认Linux的负载能力和稳定性,但是这不能证明那台机子上在内核里跑的代码(包括Linux内核及第三方驱动程序),全部没有错。Linux内核的代码if,else,for嵌套一大堆,没准在那台机子特定的条件下,激活的代码就有Bug。
Linux的netfilter,可是在Ring 0里面跑的,看看这个帖子,Linux Kernel Team的人是怎么说的:
[url=http://www.uwsg.iu.edu/hypermail/linux/kernel/0605.1/0008.html]Re: [PATCH] fix mem-leak in netfilter[/url]
这个源代码可以在这里找到:[url=http://www.promethos.org/lxr/http/source/net/ipv4/netfilter/ipt_recent.c]http://www.promethos.org/lxr/http/source/net/ipv4/netfilter/ipt_recent.c[/url]
看里面逻辑套的,得算是bad smell了吧。
[quote="robbin"]再说一个现象,根据我当时对memory leak的观察,用户进程使用的resident内存并没有增加很稳定,系统buffer,disk cache也没有增加很稳定,但是用户进程持续不断向kernel申请更多的内存,却从来没有向kernel回吐内存。这就好像一个人拼命喝酒,但是他的肚子就像一个无底洞那种感觉。[/quote]
用户进程向kernel申请更多的内存,如果申请成功了,使用的resident内存却没有很稳定增加,这是不是很矛盾啊。
用户进程想读写文件或访问网络只能通过System Call,内核里面的代码会跑一圈,这里面要是内存遗漏外面是看不出来的。
要想再追根问底,我看只能搭个kernel debugger追踪一下。不然就成悬案了,就像我们现在也不知道肯尼迪是谁杀的。