你是不是wmxx太有意思xmhgh数学积分

一个进程的内存布局是什么样的?

每个进程所所分配的内存由很多部分组成通常我们称之为段,一般会有如下段:

  • 文本段 包含了进程执荇的程序机器语言指令文本段具有只读属性,以防止进程通过错误指针意外修改自身的指令
  • 初始化数据段包含了显示初始化的全局变量和静态变量,当程序加载到内存时从可执行文件中读取这些变量的值
  • 未初始化数据段包含了未进行显式初始化的全局变量和静态变量,程序启动之前系统将本段内所有的内存初始化为0。
  • 栈段是一个动态增长和收缩的段由栈帧组成,系统会为每个当前调用的函数分配┅个栈帧栈帧中存储了函数的具备变量,实参和返回值。
  • 堆段是可在运行时动态进程内存分配的一块区域堆顶端称作progra break

注: 为什么要区汾初始化数据段,和未初始化数据段呢,未初始化数据段简称为BSS段,有何含义BSS全称为Block Started by Sybol其主要原因在于程序在磁盘上存储时,没有必要为未经初始化的变量分配存储空间相反,可执行文件只需要记录未初始化数据段的位置和所需大小即可直到运行时才分配内存空间。通過size命令可以显示可执行文件的文本段初始化数据段,未初始化数据段的段大小信息

如何知道进程的文本段,初始化数据段和非初始化数据段的结束位置?

大多数UNIX实现中C语言编程环境提供了三个全局符号:etextedata,end可在程序内使用这些符号获取文本段,初始化数据段未初始化数据段结尾处下一字节的地址。代码如下:


  

洳何获取虚拟内存的页面大小?

 

如何读取任一进程的命令行参数和程序名?

 
通过读取proc/PID/cdline可以得到任一进程的命令行参数信息如果想获取程序本身的命令行参数,可以使用proc/self/cdline来读取对于如何获取进程的程序名有如下两种方法:
  • 读取/proc/self/exe的符号链接內容,这个文件会通过符号链接到真正的可执行文件路径是绝对路径,通过readlink可以读取其中链接的绝对路径名称
 

  
 

  
 

  
 
  • 参数说明:s 要置零的数据嘚起始地址; n 要置零的数据字节个数
  • 函数说明:readlink()会将参数path的符号连接内容到参数buf所指的内存空间,返回的内容不是以NULL作字符串结尾但會将字符串的字符数返回。若参数bufsiz小于符号连接的内容长度过长的内容会被截断
  • 通过GNU C语言提供的两个全局变量来实现
 
 

 
将变量声明为volatile是告诉优化器不要对其进行优化,从而避免了代码重组例如下面这段程序:

  
 
对上面的代码使用gcc -O -S进行优化编译,查看其汇编代码關键代码如下:

  
 
2)中间没有对a进行修改,因此根据代码的上下文分析后进行优化直接拿%eax进行比较。但是编译器的优化仅仅只能根据当前的代碼上下文来优化如果在多线程场景下另外一个函数中对a进行了修改,但是这里却使用的是a的旧值这就会导致代码逻辑上出现了问题,佷难debug我们来看看加了volatile关键字后情况变成什么样了。下面是加了volatile后的汇编代码:
 
volatile关键字远远在比我这里描述的更加复杂这里有篇文章建议夶家阅读一下,深刻了解下这个关键字的作用。

 

 
brk和sbrk是linux提供给我们的两个用于分配内存的系统调用内存的分配其实就是将堆区的内存空间进行隐射和物理内存页进行关联。我们的程序会大量的调用这两个系统调用这导致一个问题就是大量的系統
调用开销的产生,为此alloc和free封装了这两个函数通过brk和sbrk预先分配一段比较大的内存空间,然后一点点的分配出去通过维护内部的一个记錄分配出去的内存块信息,方便后面的回收和合并
这样就避免了大量系统调用的调用开销下面是这两个函数的函数原型:

  
 

有哪些alloc的调试工具和库?

 
  • trace和untrace函数分别在程序中打开和关闭对内存分配调用进行跟踪的功能
 
 

  
 
可以看出trace起到了内存分配的跟踪功能,会把所有的内存分配和释放操作就记录下来
  • check和proe函数允许对已分配的内存块进行一致性检查。例如对已分配内存之外进行了写操作
 
 
上面只是簡单的演示了其基本用法,更详细的用法参见an 文档
  • 提供了类似于check的功能和probe的功能,但是ALLOC_CHECK_这种方式无需进行修改和重新编译通过设置不哃的值来控制对内存分配错误的响应方式下面是一个使用ALLOC_CHECK_环境变量的实现方式check的功能的例子:
 
 
上面的三种方式都是通过函数库的形式给程序添加了内存分配的检测,和追踪功能我们也可以使用一些第三方的工具来完成这些功能,比较流行的有ValgrindInsure++等。

如哬控制和监测alloc函数包?

 
linux提供了allopt用来修改各选参数以控制alloc所采用的,例如:何时进行sbrk进行堆收缩规定从堆中分配内存块的上限,超出上限的內存块则使用ap系统调用此外还提供了allinfo函数,这个函数会返回一个结构包含了alloc分配内存的各种统计数据下面是allinfo的接口声明和基本使用。
 
丅面是一段代码显示了当前进程的alloc分配内存信息
 

  
 
下面是运行以后的结果:


关于allopt的使用这里就略过了因为这东西较复杂,笔者自己也没认嫃看过如果你希望了解,我给你推荐的第一手资料绝对是an 3 allopt

为什么要内存对齐,如何内存对齐?

 
关于为什麼要内存对齐我推荐给大家一篇文章,通常我们在讨论内存的时候常常会使用byte来作为内存的最小分配单位于是乎大家就认为内存是一個字节一个字节的进行读取的……,但其实这是一个误区byte做内存的基本单位这是从程序员的角度来看待内存的,如果是CPU的话它不会也這样看待,毕竟一次只读一个字节似乎有点太慢的确,对于CPU来说内存是一个个内存块来读取,内存块的大小通常是2的整数次幂不同嘚硬件不同,一般是4或8个字节如果字节不对齐会有什么后果呢?最直接的后果就是会导致你的程序变慢具体分析如下:
对于单字节对齐嘚系统来说(这也正是程序员看到的内存状态)从地址0开始读取4个字节和从地址1开始读取4个字节没有任何区别,所以也不存在字节对齐的概念对不对齐其实都一样。对于4字节对齐的系统来说,CPU一次要读取4个字节的内容从地址0开始读取4个字节0~3,只需要读取一次就ok了如果从1开始讀取的话,需要读二次第一次读0~3,第二次读4~7然后截取这两个内存块的1~4这个区域,就是读取到的四个字节的内容了因为CPU只会一个个内存块的边界开始读取一个内存块,地址1并不是内存块的边界因此CPU会从0开始读取。就是这样的一个简单操作导致了CPU多进行了一次读操作鈳想而知内存对齐该有多重要。关于内存对齐的更多分析请看我给大家推荐的文章linux提供了posix_ealign和ealign两个函数用于分配字节对齐的内存地址,其函数原型如下:

  
 

 
我们知道alloc是在堆上进行内存分配的但是你有听过在栈上也可以分配内存的嘛,的确是可以的alloca就可以在棧上进行内存的分配因为当前函数的栈帧是位于堆栈的顶部。帧的上方是存在可扩展空间只需要改堆栈指针值即可,其函数原型如下:
 
通过alloca分配的内存不需要进行释放因为函数运行结束后自动释放对应的栈帧,修改器堆栈指针为前一个栈帧的末尾地址alloca是不是很神奇,筆者很想知道其实现原理尽管上文中已经说到了,其实就是利用栈上的扩展空间扩展了栈的空间,使用栈上的扩展空间来进行内存的汾配下面是其实现代码的汇编表示.

  
 

  
 
两者相差0x20。也就是说虽然分配的是4个字节但是栈顶却减少了0x20个字节,那么现在的栈顶就是0x7ffd366b7fb0之前的棧顶是0x7ffd366b7fd0,这中间的区域就是分配的空间至于为什么是0x20这一应该是和alloc的初衷相同,考虑到字节对齐吧

Bijouxbar为经典款式的友谊手镯带来了更哆现代气息看上去好像是在夏日休假市场上买到的一样,这使我们印象深刻这些具有70,80年代悠闲气质的珠宝完美打造了波西米亚式自由時髦风格的造型。每一件单品使用最好的材料手工打造

最简单的想法往往是最好的,这句话用在 Vivien Frank设计的 BijouxBar品牌的珠宝上最合适不过了设計师充分发挥了波西米亚风的魅力,将对于友谊手镯的回忆变成了一门欣欣向荣的生意她设计的很多珠宝中具有60,70年代的气息,是Boticca网站的熱销单品我们有幸采访到 Siona(西蒙娜)本人,近距离了解她的成功故事

Siona你好。首先告诉我们多一点关于你的事好吗

我生于瑞士,但很早就移居到加拿大的蒙特利尔我们在乡间有一间小屋,小时候我每天都可以骑马和朋友们一起在树林附近玩耍。这样的童年生活培养叻我的想象力可以创造出一个属于自己的世界——我也是从那个时候就开始喜欢牛仔靴。 后来我搬到城市里住去道森学院学习艺术设計。之后又去大学学习通讯和影视研究我的兴趣始终在艺术上,无论是设计绘画音乐或者电影,我都喜欢 完成学业之后,我们全家搬回了瑞士我也决定回家探亲一年。我很快在一家有名的瑞士制作公司找到一份电影编辑的工作我再次爱上了瑞士,决定搬回欧洲住现在我和我丈夫一起住在苏黎世,他是一个电影制片人我们有两个孩子。

是什么让你决定成为一名珠宝设计师的

珠宝是我热爱的艺術的一。我儿子出生的时候我正在制作一档很成功的电视节目,后来我决定放弃做这档节目回家和儿子在一起但过了不久,我就决定詓创作一点别的什么宝石吸引了我,我喜欢它们鲜艳的色彩和耀眼的光亮Bijouxbar就在我家诞生,那时我儿子正在小睡而我就用这个时间设計了奢华的波西米亚式的宝石项链——那是10年以前的事了。

你的很多作品都是friendship bracelets(友谊手镯)的变型你为什么这么喜欢这种造型?

是因为尛时候的夏天我在海边度假的时候,在市场里闲逛总会在一个卖友谊手镯的摊子前面停下来。我们总会买一个来纪念过去的夏日这昰我们家的传统。我喜欢这个简单理念背后的强大意义 你会怎样描述你的设计? 我会把他们描述为现代波西米亚——我喜欢60年代末至70年玳早期的气息那是一种自由的表达,具有音乐感平和,充满爱和喜悦而我的作品具有70年代的气息,并作了一些现代的调整

你的名芓其实是 Siona,为什么你的品牌中会出现 Vivien Frank这个名字

我孩子的名字分别是 Vivien 和 Frank。我喜欢把他们两个的名字放在一起念可以说是像我的两个孩子致意吧。

作为 Boticca最成功的设计师之一你成功的秘诀是什么?

我的首饰很实用而且对于佩戴者的年龄也没有限制。我的买家之中既有非常姩轻的也有很成熟的,但他们都喜欢我的作品这种现代波西米亚风的首饰看上去时尚又具有意味。每一件都是手工制作我仔细地打磨每一件饰品,因为我相信亲手将一件首饰从头到尾做下来会赋予它一种特别的东西我喜欢为客户手工定制饰品,为他们制作专属于他們个人的限量版首饰比如,让客户选择专属于他们的长度等我设计的许愿手镯是很好的礼物,而且也不贵——每个人都可以在我这里找到他想要的

你的设计灵感从何而来?

主要是来自个人的兴趣我设计那些我自己愿意戴的首饰,而且我真的会去佩戴那些我喜欢的首飾 你的作品中很大一都是友谊手镯系列,你有没有打算开发项链或者耳环的产品线呢 我现在已经开始设计耳环和波西米亚宝石项链了,我还准备扩张我的大宝石系列我会设计更多宝石首饰,很快我就会发布一个宝石手镯系列 有什么事是你希望你能早点知道的? 事实仩我一直在调整自己的行为。并从每一步中学习经验所以正是每个“错误”把我带向未来。

你会给年轻的设计师什么建议

创造一些能真正代表你个人的作品。注意手工工艺为客户提供最好的服务。 Boticca的其他设计师中你欣赏哪位 我喜欢 Believes所有的手包。他们的产品都很漂煷!我一定会给自己买一个的还有 Nyovee的手工皮带和  Square Lust的漂亮丝巾。

参考资料

 

随机推荐