嵌入式开发的内存无疑是非常吃紧的。特别是一些老设备(512MB内存),之前的一台终端设备因为内存占用过高,出现了运行出错,进程管理的APP直接杀死了占用最高的媒体APP,导致视频输出出现异常。
于是进探索了内存优化之路。在确保长时间运行内存不会增加(没有内存泄漏)后,首先查看 /proc 下的进程 内存占用的smap 信息:
cat /proc/<pid>/smaps|grep -v ' 0 kB'
通过观察不难发现大量的内存占用都在栈上。由于这个APP是一个多线程进程,一个线程就有一个栈,导致了进程申请的内存大量被用于线程栈的申请上,每个栈8MB,仅10个线程就占用了100MB的虚拟内存空间。
一个进程占用99MB内存,11个线程栈的内存占了88MB。那么方向就很明确了。减少栈的大小即可。
首先想到的是,直接进行全局的配置系统默认栈得大小,因为目前Linux程序的线程使用的都是默认的参数,即采用系统默认的栈大小进行开辟线程的栈。使用ulimit -s 指令在启动脚本加入:
ulimit -s 1024
以上就将系统默认栈设置为1024KB,单位是KB。启动系统,不巧的是,有些APP运行出现了异常,猜测界面APP使用了大量的变量,导致栈的溢出,APP直接就退出了。缩小系统栈还是有一定的风险,而且不知会不会引入其他的问题。
想着既然Linux系统一般都是使用pthread启动线程,而且子线程一般变量较少,不需要很大的栈空间,那么我们可以通过pthread_create的pthread_attr_t进行参数的设定设定进程生成的线程栈,达到缩小进程内存占用的目的。
将佘艳的线程生成
int thread::startThread(callable *c) { int const res = pthread_create(&handle_, 0, &posix_thread_proxy, static_cast<void*>(c)); if (res != 0) { delete c; return -1; } return 0; }
改为这样创建线程(这里的stacksize的单位是字节)
int thread::startThread(callable *c) { pthread_attr_t thread_attr; pthread_attr_init(&thread_attr); pthread_attr_setstacksize(&thread_attr, 1024*1024); ///< 1MB int const res = pthread_create(&handle_, &thread_attr, &posix_thread_proxy, static_cast<void*>(c)); if (res != 0) { delete c; return -1; } pthread_attr_destroy(&thread_attr); return 0; }
即可将原来的8MB栈大小改为1MB,效果显著。
top指令查看 左边为修改前,右侧为修改后
ps -o pid,comm,rss,vsz 指令查看 左边为修改前,右侧为修改后
可以看到线程多的APP占用基本缩小了一半多。