编译器:几种编译器的内存管理和LX管道的内部实现

天闛/xy忏 n
关于某个作业的地址空间大小为3K ,在内存中占4K的疑问.......

今天看软设的书,突然看到这个问题........ 在内存中,确实存在碎片的问题,一般可以采用"紧缩"的方式(搜索内存找到连续的一片3K大小的空闲内存),还有种方式就是 "分页存储管理"..
如内存有2个为2K的空闲内存,把作业划分为2K和1K 分别存储与内存那2个2K空闲区内.
所以分页的目的就是离散分配,提高内存利用率


##########################
过了真是个事........过了 过了....HO
一个有趣的问题又让我长见识了,CTQ也喜欢思考问题...可我不好象平时不怎么思考..但遇到有兴趣的问题却很想搞个所以然来.....技术真的是很迷人的一个东西....小心被毒害了.....
先看两段代码

struct Sqlist
{
int num[row][lan];
double *n1=new double[length];
//double *n2=new double[row][lan];//上面那句可以申请到堆内存 ,这句不行
}
int mian(..)
{
Sqlist *heap=new Sqlist;//申请堆上面的内存
Sqlist stack;//申请栈上面的内存
...
delete heap;
}
上面两种方法都可以,那哪种好呢?
原来 堆内存的特点 空间大 速度慢(不是连续的内存块,需遍历搜索) 用户可控制 必须回收
栈上面 空间小(WIN一般2M) 速度快(好象说是在低地址申请) 用户不可控制 OS自己回收

以上差不多是这两种的区别了



##########################
看到一个朋友的BLOG写到了 几个LIB的内存管理
"先来看个程序段
char * a=(char *)malloc(9);
char *b=a;
free(b);
//-----
如何确定要释放的空间大小呢? 答案是cookie
就是在申请的内存空间有一个cookie的东西,它记录的是这个内存块的大小,和其它的信息"
上面是朋友在BLOG上的原话.

后来经过进一步的发现, 其实不同编译器的原理却不同....

不过看得出来 其实很多问题去发现 你就发现很多奇妙的东西

比如上面说的的cookie.... 学过C++编程或者C 的都可能知道 在申请堆栈上的 内存时是用new(),和malloc()申请内存的
但又有多少人想过上面的数字 9 他怎么实现的呢??? 又怎么处理这个 9呢?

在VC平台上是用HeapAlloc分配内存 用HeapSize得到内存大小 分配的头部都有32字节. 在每个申请的内存块中的头部 都会留有4byte的大小来记录这块内存快的大小等其他信息, 这就上上面所说的cookie(小甜饼)了.

但是朋友可能把这个cookie扩大到了C++所有平台上去了(也许是写的时候笔误).
经后面的了解 ...
在Builder c++用他自己的(MemoryManager),用VirtualAlloc分配了固定大小的m Byte,当需要更大的空间时,就再申请,我觉得也就是它说的分配的空间一定是m Byte的整数倍,所以就不用那个COOKIE来记录内存大小了.

也许有朋友会问,可以不用那个COOKIE嘛~~ 对,我们可以用灵活性来换取空间和效率, 也就是侯捷先生 所说的申请固定大小,但是用户就不能"任意"指定大小了,和上面的BCB类似,不过BCB可以任意指定申请内存大小,不知道怎么实现的......

在CSDN上发了 想了解下GCC内存分配 的帖子....期待中.... 呵呵~~~

##########################
管道的内部实现还在啃中....................
无名管道:
管道是半双工的,数据只能向一个方向流动;
需要双方通信时,需要建立起两个管道;
只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
下面是一个例程 基本上只是用了特殊的文件流
#inlucde <unistd.h>
#include <sys/types.h>
#ifndef READ_BUF_MAX
#define READ_BUF_MAX 5000
#endif
#ifndef WRITE_BUF_MAX
#define WRITE_BUF_MAX 4096
#endif
//保证读大小比写大小大
int main(int argc,char *argv)
{
int pipe_fd[2];//创建两个管道文件
pid_t pid;//创建进程
char r_buf[READ_BUF_MAX];//读数据BUF
char w_buf[WRITE_BUF_MAX];//写数据BUF
int wnum,rnum;

memset(r_buf,0,READ_BUF_MAX);//初始化BUF
menset(w_buf,0,WRITE_BUF_MAX);
if(pipe(pipe_fd)<0)
{
printf("pipe create wrong&#92;n");
return -1;
}
if((pid=fork())==0)//判断是否是子进程
{
close(pipe_fd[1]); //管道的单向性 决定了 要读必须先关闭 写端 这里是关闭写端
while(1)
{
sleep(1);//沉睡1ms 不知道是否是把进程挂起???
rnum=read(pipe_fd[0],r_buf,500); //每次读取500个字节
hand_to_cmd(rnum);//处理函数 用于应用了
printf("In the childprosecess is %d &#92;n",rnum);
}
close(pipe_fd[0]);//记得关闭管道
return 0;
}
else if(pid>0)//判断在父进程
{
close(pipe_fd[0]);//关闭读端
w_buf=writefun(sizeof(w_buf));//写操作
//memset(r_buf,0,sizeof(r_buf));
if((wnum=write(pipe_fd[1],w_buf,sizeof(w_buf)))==-1)
printf("wite error&#92;n");
else
printf("Write num is %d &#92;n",wnum);
close(pipe_fd[1]);//关闭写端
}
}

//上面实现的是一个简单的读写管道操作~~
//有名管道
#define FIFOMODE (O_CREAT | O_RDWR |O_NONBLOCK)
#define OPENMODE (O_RDONLY | O_NONBLOCK) //只读模式
#define WOPENMODE (O_WRONLY | O_NONBLOCK)// 只写模式
#define FIFO_SERVER "myfifo" //设置管道模式 也就是 上面的那些关闭阻塞操作

int main(void)
{
char r_buf[100],w_buf[100];
int fd[2];
int r_num,w_num;
pid_t pid;
memset(r_buf,0,100);
menset(w_buf,0,100);

//创建有名管道 设置可读写 ,无阻塞
if(mkfifo(FIFO_SERVER,FIFOMODE)<0)&&(errno!=EEXIST))
{
printf("create error&#92;n");
exit(1);
}
if((pid=fork())==0)
{
if((fd[0]=open(FIFO_SERVER,OPENMODE))<0)
{
perror("open");
exit(1);
}
while(1)
{
if((r_num=read(fd[0],r_buf,100)))<0)

printf("no data&#92;n");
else if(r_num!=0)
printf(" r_buf is %s&#92;n",r_buf);
sleep(1);
}
}
else if(pid>0)
{
if((fd[1]=open(FIFO_SERVER,WOPENMODE))<0)
{
perror("open");
exit(1);
}
//################## 写不下去了

和朋友聊的兴奋 都不想去自习了~~~~~ 呵呵~~

##########################
说说对于NEW() 和DELETE() 两个关于C++内存使用问题,也是今天学到的.
这里的前提问题是 不考虑不同的编译器环境
下面是C++中 NEW 和 DELETE的原型

void *operator new(size_t) throw(std::bad_alloc);
void *operator new[](size_t) throw(std::bad_alloc);
void operator delete(void*) throw();
void operator delete[](void*) throw();

比如 "new int" 就调用 operator new(sizeof(int)); 对于 new char[10] 调用 operator new (10*(sizeof(char)) ; (当然对于不同的编译器 ,他们的内存对齐又是不一样的)
delete 也是同样的道理

这里牵涉到另一个问题了 就是 内存检测.. .........哟系~~~ 有机会 偶也想做一个
Tags:  c编译器 java编译器 c语言编译器 编译器

延伸阅读

最新评论

发表评论