由于程序最终是在一款嵌入式平台上运行.由 python+clutter 的程序在pc上运行内存可以非常理想的释放,而在嵌入式平台上却不能释放.
开始时,一直怀疑是内存泄露的原因,但是前面的工作将内存泄露的原因也排除了.
我用c写的程序在pc上运行,没有明显的内存泄露.
后来,我将两个一模一样的程序,分别在两个平台上运行,得到的内存记录却完全不同,
在pc上能良好释放,但是在嵌入式平台上,却还是不能释放.
考虑到两种平台,有区别的地方可能就是opengl,在pc上用的是OpenGL,而在嵌入式平台上,用的却是OpenGL ES.
所以我又写一个最简单的clutter程序,仅是产生图片,然后销毁掉,在两种平台上,查看区别.
但是結果还是不同,所以怀疑是OpenGL不同导致的.怀疑是由于OpenGL的内存池不释放造成的. 但是,同事却告诉我说,OpenGL不存在内存池.
今天,又想到,是不是因为内存分配没有对齐,导致很多内存碎片的问题呢.所以去查g_malloc函数,到Memory Allocation一节时,看到对这一节的描述:
These functions provide support for allocating and freeing memory.
g_malloc()
with g_free()
, plain malloc()
with free()
, and (if you're using C++) new with delete and new[] with delete[]. Otherwise bad things can happen, since these allocators may use different memory pools (and new/delete call constructors and destructors). See also g_mem_set_vtable()
.
其实的malloc的实现并非简单调用brk/sbrk,为了考虑效率glibc有“三级”优化措施,即:
1. “小内存”分配通过 fastbin 链表实现;
2. 一般的内存分配在堆上分配,该区域称为:memory arena;
3. 比较大(比M_MMAP_THRESHOLD设定的值更大)的内存采用mmap分配,采用mmap的好处在于free后立即交还给系统,而不会被锁定而浪费内存;
在程式调用free时,glibc并不会每次调用sbrk,相反glibc会把放到暂时的内存池中,以提供下一次malloc的操作使用,这样能够达到内存分配效率的优化。
控制内存分配的函数是mallopt,其原型如下:
int mallopt(int cmd, int __val);
cmd的取值为:
M_TRIM_THRESHOLD -1
M_TOP_PAD -2
M_MMAP_THRESHOLD -3
M_MMAP_MAX -4
M_CHECK_ACTION -5
M_PERTURB -6
其含义如下:
M_TRIM_THRESHOLD
当能够被释放的内存堆积到该值时进行正真的释放(sbrk)操作;
M_TOP_PAD
内存分配时头部的附加长度。假如程式调用malloc分配1024k内存,但glibc并不会仅仅分配1024k,还需分配更多的内存(一部分用来进行glibc自身的内存分配管理使用)。
M_MMAP_THRESHOLD
假如需要分配的内存超过该值,glibc将采用mmap分配内存。
M_MMAP_MAX
用来控制最多的mmap的数目;
实例:mallopt-trim.c
事实上以上参数能够通过相应的环境变量来设定而不必修改程式,比如:
MALLOC_TRIM_THRESHOLD_=1024 ./program
对相同的c程序,在pc和嵌入式平台上测试結果相同,确定在嵌入式平台上内存不释放就是这个原因.但是,我们的程序是python程序.
看到可以mallopt函数来在代码中设置.
在c程序中,可以添加在main函数内的开头,但是,我们在python中是调用c的库,并没有main函数.
然后我觉得应该在控件创建开始的地方进行设置,但是测试結果却没有改善,看来设置并没有效果.
后来想到,既然以命令行添加环境变量的方式在c可行,那么在python中也是一样的啊,我只要设置python的环境,那么glibc库的运行环境继承来自python程序的运行环境,肯定也可行.
MALLOC_TRIM_THRESHOLD_=1024 MALLOC_MMAP_THRESHOLD_=1024 ./movie.py
当然参数值的設定应该是继续优化,网上有说最好一页大小为宜,即4k