[笨叔点滴11] malloc惹的祸
“ 一个小伙子用2000元其中的1500元给MM买了部手机,留500元吃饭开房,骑着电瓶车去找MM,MM说:你是一个好人,可是我们真的不合适。”
上面段子是个笑话,如果我们优化一些呢:
一个小伙子用700元租了一辆BMW5,然后去批发市场300元买了99朵玫瑰,告诉MM他喜欢手牵手去那些浪漫的小吃店,最多消费100元。
MM说,你真帅!
看,这就是优化的力量!
昨天在笨叔的VIP群里,小伙伴很happy的讨论一个问题。
他们讨论的程序是这样的:
这个程序还挺有意思的。一个while循环里,一直在使用malloc()来分配内存,直到世界尽头。这个例子里,其实涉及到内存管理挺多的知识点。
malloc函数返回的内存是虚拟内存还是物理内存?什么时候分配物理内存?
malloc这个函数什么时候会导致分配不成功?
malloc分配的页面算是什么页面?
上面那个程序究竟内存吃到哪里去了?
-----?----
首先看:
第一个问题,malloc分配的内存究竟是虚拟内存还是物理内存。这是研究这个问题的第一个最基本的认识了,如果这个认识搞错了,这个问题讨论就走偏了。其实大家把为啥操作系统需要区分虚拟内存和物理内存这个问题搞明白了就行了,就会明白为啥malloc返回的内存是虚拟的。
【关于malloc是怎么分配的,可以看《奔跑吧Linux内核》第2.8章,这一章开头的几个问题,也是很经典的哟】
那既然是虚拟的,什么时候会需要物理内存呢?总不能天天谈论虚拟,而没有物理内存吧,那也太虚幻了,物理内存就是让你感觉到踏实。
[第三个问题:关于malloc之后,是怎么分配出物理页面的,以及是啥类型的物理内存,建议大家看《奔跑吧Linux内核》第165~168页]
第二问题,啥情况会让malloc函数分配不成功。这个问题,有点难度哟,要弄明白,先上张图如何。
这张图是32位处理器,堆空间的示意图,它是在数据段结束的地方到1GB的地方,这么大的地方就是给堆空间用的,也就是malloc。但是glibc会使用上面的mmap空间,所以如果上面程序跑着32位系统里,那么3GB的虚拟空间都有可能给这test吃满了。
那么对于64bit程序,最大可以分配的虚拟空间是多大呢?在x86里就是这个宏定义的
#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE)
那它大概有多大呢?大家可以算一下,大概是128TB左右。
第4个问题:那分配失败有两种可能,一种情况是虚拟空间没有了,也就是吃掉了这128TB的空间,还有一种可能是物理内存不够了,也是malloc这个机制本身的管理系统也是需要维护成本的。如果没节制的一直的使用malloc,其本身也是吃掉内存的。这就是管理的两面性,很多时候管理成本也是考量因素。
对照上面两个图,看Active (anon),后面这个图被吃了4GB多的,所以干跑malloc也是有管理成本的。
大家有兴趣可以,把上面程序修改MEM_SIZE的大小,来观察他们的变化:
比如在最后面增加一个sleep函数,让程序停留在那里,然后我们来解剖。
大家观察到什么好现象,可以在评论区里留言哟
[往期精彩]
[笨叔点滴5] git rebase和git merge究竟有啥区别?
[笨叔点滴2] 为啥子ARM32体系结构中每个处理模式都有一个单独的栈?
[笨叔点滴1] 为什么do_page_fault函数里代码需要判断用户态还是内核态?
高级运维必杀技:如何图形化单步调试RHEL/Centos 7里的内核?