linux程序设计需要注意的问题
-
socket的服务器第二次启动显示无法bing到对应地址和端口上
这个使用netstat -anlp 查看对应的端口状态后,发现是TIME_WAIT状态,这个状态是不能连接的,应该如下解决
int one = 1; setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&one,sizeof(one)); setsockopt(sockfd,SOL_SOCKET,SO_REUSEPORT,&one,sizeof(one));
设置one=1 就是启用,one=0就是取消
项目说明:
SO_REUSEADDR : 设置处在TIME_WAIT的地址可以重复使用.
SO_REUSEPORT : 设置处在TIME_WAIT的端口可以重复使用.
注意 : 编写服务器程序的时候,应该都设置这两个选项,如果没有,服务器将不能立刻重起
对程序内存结构和程序存储位置的理解
之前看过许多有关系统中,对内存分配的一些文章,一直一知半解,直到调研一个系统调用,才真正的弄明白是怎么回事.有一个重点就是,这里说的全局数据区,全局,说的不说c++中的全局的概念,如果那样理解很容易感觉模棱两可,这里说的全局说系统看来,不是一个程序的看待,对系统来说,一个程序的全局就是,需要在程序运行前准备好的内存,对于c++中的变量,系统看来只有三种:全局,stack,bss, 其他两个,stack管程序调用,bss指需要,但是运行的时候才能知道内容.加载慢的一个优化手段就是,调整程序,让bss代替data,具体为什么,下文会说,
这个内容想写写来源于对一个系统调用的研究 brk(void* addr), 某些程序加载的时候cpu很高,使用strace -p PID查看以后,发现他一直执行brk这个系统调用.
brk: 调整程序的数据段,把数据段的地址往高地址调整,,,,,这个有啥用?地址段不是应该加载的时候分配好的吗?有的说这个还能分配动态内存,动态内存不是在heep区分配的吗?总之疑点重重.
一般系统中的地址分配都是从低到高, 依次是:
text段 => 存放指令代码,在可执行文件中也由这一部分,系统会把文件中的text端拷贝到内存里
bss段 => 未初始化的全局数据区,一般系统会弄成0,这一部分在可执行文件中是没有的,只是记录一下需要多少这种空间
data数据段 => 这一部分比较特殊,下文会具体说明,可执行文件中可能有也可能没有.
——-> 这有个指针(系统用的,不过用户态可以通过调用修改) _edata
heep堆 => 这是通常 认为 的malloc申请内存的地方,其实也不一定的,下文会说
stack栈地址 => 栈地址,通常的函数调式都会用到的,
==>
==>
3G以上就是内核区了,用户态就别想自由使用了.
brk的功能就是,把 _edata的地址网高出推,往 heap这边推,可以想象,brk把_data往heep推了,heep能分配的空间肯定就少了啊,
对的,是这样的,
有关brk分配内存的说明
c语言中分配内存,当然是使用malloc了,brk分配内存的功能,就是在这里的,glibc对malloc的实现,是如果分配的内存在 126k以内,就使用brk分配,把brk往heep端推一点,多余出来的数据段,返回给用户,用作动态内存,当读写这个内存的时候,就会引发一个 缺页中断 让系统在物理内存里分配段内存.126k以内都用brk,我们平时试试的基本都是使用brk分配的啊,我不信!!,我写个程序给你证明
#include<iostream>
#include<unistd.h>
#include<stdlib.h>
using namespace std;
int main(){
void*p = malloc(1);
cout<<p<<endl;
int a = brk((void*)((char*)p+1000)); //这句调步调影响下次malloc返回的地址
//int a = brk((void*)((char*)p+1));
cout<<a<<endl;
void* d=malloc(1);
cout<<d<<endl;
return 0;
}
一开始我使用 brk(p+1) 程序直接崩溃了,后来查了一下两次malloc的地址差,发现一次malloc 已经把_edata的地址上调了460了,如果我在上调,只能调这个数更大的范围了, 这里有个隐含规则 brk 的地址,只能往高处调,不能往低处调,因为已经调好的内存,可能已经分配了,我们私自把地址往下调了,brk也返回成功0,可是程序会直接崩溃.
如果malloc申请的地址超过了126k,才会调用mmap到heap区去申请内存. brk和heap是linux系统调用,malloc是glibc的函数,不是系统调用.
如果_edata只能往上调,那麽,即使malloc把内存释放了,把_edata调下来,也只能依次释放的,可是用户程序不一定这样来,这不就是浪费吗?是的,是这样,用户free,这个地址的一段内存就不能回收了,只有当最高处的地址被free了,才能把_edata调下来,同时通知系统,取消映射.malloc默认没有一个一个字节的向高地址加,而是一次就加许多,这个许多如何知道呢,这个和系统分配的页大小有关,查看办法如下:使用getconf PAGESIZE 查看系统的页大小