线程空间优化

来源:互联网 发布:云计算就业工资多少 编辑:程序博客网 时间:2024/06/05 09:16

线程堆栈大小http://blog.csdn.net/nokianasty/article/details/7600321

C++内存分布http://blog.csdn.net/morewindows/article/details/6851681

线程堆栈分布http://bbs.csdn.net/topics/390391357

在看了这三篇的讨论后,对于线程堆栈,内存分布等有了一点了解,以上引出几篇文章,再做一些自己的总结:

首先,引出搜索者方面问题是因为多线程编程中,一些线程没有及时销毁,导致存储不足的情况,于是探究一些解决方法。

1).线程分为内核态与用户态。

首先是内核,指的是操作系统中最基础的一些部分,提供一些分装的结构,方法,对外部限制访问权限。即对于用户是一个只知道接口,不知道内部的结构。

内核态线程,即对内核可见线程,有比较小的数据堆栈,易于调度,调度依赖于操作系统,一个线程阻塞,操作系统依据自己的策略调度其他可用线程,实现线程的并发。

用户态线程,对于内核不可加,一个线程阻塞时,如果用户不手动调度,整个进程都会阻塞。

由于在项目中用CreateThread创建的线程已经是内核态的线程,故这里没有改进。


2).存储变量分为五个区,堆,栈,自由区,全局/静态区,常量区

摘自以上某篇文章的示意图如下:


其中new []使用的是堆,全进程共享,查了一些资料,说堆最大为2GB。;malloc,局部变量,函数调用时的参数传递会用到栈,如int *a=int[n]。

通常,每个线程一个栈,每个进程一个堆。所以线程数目的瓶颈在于线程自己的堆栈。这里的堆栈仅仅指的是栈。Visual C++编译器默认设置是每个线程的堆栈大小是1MB。

32位的计算机,地址内存空间为2^32,即4G,其中2G分配给用户使用,给自己创建的线程分配的是虚拟内存。

一般当线程数为2000*1MB=2G时,会超过一般的限制,报错。相应的64就最多8000个线程。

当然,如果在创建线程时指定较小的堆栈大小,就应该可以创建较多的线程。

查看项目代码中buffer的代码段,如下:

m_p = new C* [Size];
   for (int i = 0; i < Size; ++ i)
      m_p[i] = NULL;

也就是说,这里的缓冲区空间大部分用new 来创建,也就是放在进程共享的堆区,而不是线程的栈区,我们也就能够通过修改每个线程的栈的大小来减少空间。

在VS2010下设置有两个入口:

A.项目配置


B.CreateThread调用时的第二个参数;

运行时取其中较大的一个。

于是,解决方法其中之一可以为修改线程栈大小。


3).然后又接触到了一个概念:线程池,查找相关的博客http://blog.csdn.net/conceptcon/article/details/9268573

这篇博客比较详细地介绍了线程池的概念,自己归纳总结如下:

诸如服务器端,有时候要起许多处理短任务的线程,即线程实际执行的时间比线程创建和销毁的时间长不了多少,这时候优化线程的创建销毁就成了一个问题。

于是引进线程池的概念,简单地说就是创建两个线程队列,一个空余线程队列,一个忙碌线程队列,来了任务,分配工作给空闲线程的第一个线程,并把这个线程转入到忙碌队列中,这样就实现了线程的共享机制。不过项目中执行的任务是文件传输型的,一般来说线程处理的时间要远远大于线程创建和销毁时间,所以如果引入线程池,应该没有多大的改进效果,所以暂时不考虑线程池。


这里对上述做一个总结,本文探讨三个方法,内核态线程,减少线程栈大小,使用线程池,只有减少线程栈大小适用于我们项目的情况。

pS:补充一点,实际运行的时候,任务管理器显示的内存占用不足100MB,线程并行有1300个是报错。通过论坛上的讨论得到如下信息:

存用的虽然少,但预留的多,每个线程都要为线程预留栈空间,所以内存虽然没用,但已经被线程“预订”了。
vc生成的pe文件默认每个线程保留栈大小是1M,所以1400个线程,就相当于“预订”了1400M空间,而32位地址空间只有不到2G,所以提示没有内存是合理的,因为确实没有更多的内存做新创建的线程的栈了。

总结就是预定了虚拟空间,虽然没显示,但已经是不能用的。

原创粉丝点击