您好、欢迎来到现金彩票网!
当前位置:老k棋牌 > 栈溢出中断 >

Linux 进程内存布局(一)

发布时间:2019-06-19 23:26 来源:未知 编辑:admin

  这篇文章中我将以介绍一个运行在x86架构的32位Linux 操作系统上进程为例,介绍进程在执行的时候的内存布局情况,事实上下述的详细内容在不同架构的操作系统上内存布局也是大同小异,大家可能通过查找一些其它的相关参考资料以获悉其它架构及操作系统上的详细情况。

  在多任务的操作系统中,每一个进程都运行在一个内存沙箱中(彼此独立)。这就是所谓的虚拟地址,在32位的操作系统下,这个地址空间一共有4GB。因为CPU可访问的最小单元是1字节=8位,32位CPU的地址总线根,故其可产生的不同地址信息的组合共有2的32次方种,即其可寻址的空间是2^32=4G。每一个地址指向了一个内存中一个特定的字节。这些虚拟地址最终会映射到实际的物理内存地址上,这个是由硬件和OS的内核通过页表完成的。每个进程操作系统都会给给它分配一组页表用以映射。当虚拟地址开启后,所有运行在机器上的软件都会采用虚拟地址,也包括了OS内核本身,因此部分虚拟地址就需要被保留给内核。

  这并不意味着内核使用了那么多的物理内存,只是那部分被保留出来的虚拟地址可由其用于物理内存的映射。内核空间在页表中被标识为不可访问的特权级更高的代码(Ring2 或更低),因此如果一个用户模式的进程试图访问这部分空间时,一个页错误的中断将会产生。

  从上图中我们可以看到,BSS和堆,堆和内存映射段(mmap)以及栈和内核空间之间都有一个随机的偏移量。这个偏移在传统的linux进程中是不存在的。这种情况下,系统中的每一个进程的内存布局都是完全一样的,这就使得试图给进程注入恶意代码搞破坏的人很容易实施操作。因为破坏者通常需要引用内存的绝对地址,如栈上的一个地址,一个库函数的地址等(execve(2)负责为进程代码和数据段建立映射,真正将代码段和数据段读入内存是由系统的缺页异常处理程序按需完成的。另外,execve(2)还会将BSS段清零)如果所有进程运行时这些地址没有任何差异,破坏者就可以通过观察一个现有进程的各地址再计算也他要攻击的目标程序地址,从而达到目的。所以现代的Linux都加入了这个随机的偏移量,使得被攻击的目标程序函数和数据地址具不容易被猜测到。从而加强了系统进程的安全性(但32位地址空间的布局安排已经很紧密,局限了这些地址的随机化)。

  进程运行时,其内存的映射情况可以在/proc/进程号/maps中查看到,如果将进程号替换为self,则可以查看当前运行进程自己的内存映射情况。故可用cat /proc/self/maps 来查看cat进程运行时的内存映射情况,

  如下所示(下面是两次运行该命令的结果,可以看到由于随机量的作用,堆,内存映射段,栈的起始地址每次运行都有所变化):

  实际上现代Linux系统也允许让程序的这些变化的起始地址固定下来,只需要通过设置全局变量randomize_v a_space的值为0,这个变量的默认值为2。用户可以通过设置/proc/sys/kernel/randomize_va_space 来停用该特性。

  当随机化特性停用后,再次运行上述命令就会发现,堆和mmap以及栈都从固定位置开始了,栈的起始位置为0xc0000000,mmap区域的起始位置为0xb80000000,可见系统为stack区域保留了128M的地址空间。

  但实际可使用的栈空间还受ulimit的限制,可通过ulimit -S -s limit来设定可用最大栈空间大小,缺省为8M

  编译器的工具size 命令可以报告ELF文件的代码,数据和BSS段的大小。

  可以清晰看到,字面量字符串位于代码段(其被设定为只读),若尝试对上段代码中的*s尝试操作,如*s=’p’ 或者 s[1]=’q’,则不会通过编译。

  而实际中可以大量看到类似于 char* p=”test”; 之类的代码,这类代码在编译时会被编译器报个warning出来,但能通过编译。代码中可以出现针对 *p的操作,从语法上来说是合法的。但实际上我们知道,由于字面量位于只读区,尝试对只读区的修改会引起coredump。

  因此,在声明字面量字符串时,应该加上const,这样可以避免此类dump。另外在声明字符串类函数参数时,若明确只是读取,应该加上const关键字,以避免无意中对其所指向变量的修改而引起的段错误(因为字符串类函数其使用都常会倾向于传字面量使用,这种情况下就有和以上所说的同样的问题)。通过查看linux位于string.h中的字符串相关函数的原型声明,会发现几乎都遵从这一规律。

  查看不同变量所在的地址,可对照图1中各部分所处的地址空间。注意s变量自身所在的地址和其所指向的字符串的地址

  内核总是驻留在内存中,是操作系统的一部分。内核空间为内核保留,不允许应用程序读写该区域的内容或直接调用内核代码定义的函数。

  栈又称堆栈,由编译器自动分配释放,行为类似数据结构中的栈(先进后出)。堆栈主要有三个用途:

  为函数内部声明的非静态局部变量(C语言中称“自动变量”)提供存储空间。

  记录函数调用过程相关的维护性信息,称为栈帧(Stack Frame)或过程活动记录(Procedure Activation Record)。它包括函数返回地址,不适合装入寄存器的函数参数及一些寄存器值的保存。除递归调用外,堆栈并非必需。因为编译时可获知局部变量,参数和返回地址所需空间,并将其分配于BSS段。

  临时存储区,用于暂存长算术表达式部分计算结果或alloca()函数分配的栈内内存。

  持续地重用栈空间有助于使活跃的栈内存保持在CPU缓存中,从而加速访问。进程中的每个线程都有属于自己的栈。向栈中不断压入数据时,若超出其容量就会耗尽栈对应的内存区域,从而触发一个页错误。此时若栈的大小低于堆栈最大值RLIMIT_STACK(通常是8M),则栈会动态增长,程序继续运行。映射的栈区扩展到所需大小后,不再收缩。

  Linux中ulimit -s命令可查看和设置堆栈最大值,当程序使用的堆栈超过该值时, 发生栈溢出(Stack Overflow),程序收到一个段错误(Segmentation Fault)。注意,调高堆栈容量可能会增加内存开销和启动时间。

  堆栈既可向下增长(向内存低地址)也可向上增长, 这依赖于具体的实现。本文所述堆栈向下增长。

  此处,内核将硬盘文件的内容直接映射到内存, 任何应用程序都可通过Linux的mmap()系统调用或Windows的CreateFileMapping()/MapViewOfFile()请求这种映射。内存映射是一种方便高效的文件I/O方式, 因而被用于装载动态共享库。用户也可创建匿名内存映射,该映射没有对应的文件, 可用于存放程序数据。在 Linux中,若通过malloc()请求一大块内存,C运行库将创建一个匿名内存映射,而不使用堆内存。”大块” 意味着比阈值 MMAP_THRESHOLD还大,缺省为128KB,可通过mallopt()调整。

  该区域用于映射可执行文件用到的动态链接库。在Linux 2.4版本中,若可执行文件依赖共享库,则系统会为这些动态库在从0x40000000开始的地址分配相应空间,并在程序装载时将其载入到该空间。在Linux 2.6内核中,共享库的起始地址被往上移动至更靠近栈区的位置。

  从进程地址空间的布局可以看到,在有共享库的情况下,留给堆的可用空间还有两处:一处是从.bss段到0x40000000,约不到1GB的空间;另一处是从共享库到栈之间的空间,约不到2GB。这两块空间大小取决于栈、共享库的大小和数量。这样来看,是否应用程序可申请的最大堆空间只有2GB?事实上,这与Linux内核版本有关。在上面给出的进程地址空间经典布局图中,共享库的装载地址为0x40000000,这实际上是Linux kernel 2.6版本之前的情况了,在2.6版本里,共享库的装载地址已经被挪到靠近栈的位置,即位于0xBFxxxxxx附近,因此,此时的堆范围就不会被共享库分割成2个“碎片”,故kernel 2.6的32位Linux系统中,malloc申请的最大内存理论值在2.9GB左右

  堆用于存放进程运行时动态分配的内存段,可动态扩张或缩减。堆中内容是匿名的,不能按名字直接访问,只能通过指针间接访问。当进程调用malloc(C)/new(C++)等函数分配内存时,新分配的内存动态添加到堆上(扩张);当调用free(C)/delete(C++)等函数释放内存时,被释放的内存从堆中剔除(缩减) 。

  分配的堆内存是经过字节对齐的空间,以适合原子操作。堆管理器通过链表管理每个申请的内存,由于堆申请和释放是无序的,最终会产生内存碎片。堆内存一般由应用程序分配释放,回收的内存可供重新使用。若程序员不释放,程序结束时操作系统可能会自动回收。

  堆的末端由break指针标识,当堆管理器需要更多内存时,可通过系统调用brk()和sbrk()来移动break指针以扩张堆,一般由系统自动调用。

  使用堆时经常出现两种问题:1) 释放或改写仍在使用的内存(“内存破坏”);2)未释放不再使用的内存(“内存泄漏”)。当释放次数少于申请次数时,可能已造成内存泄漏。泄漏的内存往往比忘记释放的数据结构更大,因为所分配的内存通常会圆整为下个大于申请数量的2的幂次(如申请212B,会圆整为256B)。

  ①管理方式:栈由编译器自动管理;堆由程序员控制,使用方便,但易产生内存泄露。

  ②生长方向:栈向低地址扩展(即”向下生长”),是连续的内存区域;堆向高地址扩展(即”向上生长”),是不连续的内存区域。这是由于系统用链表来存储空闲内存地址,自然不连续,而链表从低地址向高地址遍历。

  ③空间大小:栈顶地址和栈的最大容量由系统预先规定(通常默认2M或10M);堆的大小则受限于计算机系统中有效的虚拟内存,32位Linux系统中堆内存可达2.9G空间。

  ④存储内容:栈在函数调用时,首先压入主调函数中下条指令(函数调用语句的下条可执行语句)的地址,然后是函数实参,然后是被调函数的局部变量。本次调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的指令地址,程序由该点继续运行下条可执行语句。堆通常在头部用一个字节存放其大小,堆用于存储生存期与函数调用无关的数据,具体内容由程序员安排。

  ⑤分配方式:栈可静态分配或动态分配。静态分配由编译器完成,如局部变量的分配。动态分配由alloca函数在栈上申请空间,用完后自动释放。堆只能动态分配且手工释放。

  ⑥分配效率:栈由计算机底层提供支持:分配专门的寄存器存放栈地址,压栈出栈由专门的指令执行,因此效率较高。堆由函数库提供,机制复杂,效率比栈低得多。Windows系统中VirtualAlloc可直接在进程地址空间中分配一块内存,快速且灵活。

  ⑦分配后系统响应:只要栈剩余空间大于所申请空间,系统将为程序提供内存,否则报告异常提示栈溢出。

  操作系统为堆维护一个记录空闲内存地址的链表。当系统收到程序的内存分配申请时,会遍历该链表寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点空间分配给程序。若无足够大小的空间(可能由于内存碎片太多),有可能调用系统功能去增加程序数据段的内存空间,以便有机会分到足够大小的内存,然后进行返回。大多数系统会在该内存空间首地址处记录本次分配的内存大小,供后续的释放函数(如free/delete)正确释放本内存空间。

  此外,由于找到的堆结点大小不一定正好等于申请的大小,系统会自动将多余的部分重新放入空闲链表中。

  ⑧碎片问题:栈不会存在碎片问题,因为栈是先进后出的队列,内存块弹出栈之前,在其上面的后进的栈内容已弹出。而频繁申请释放操作会造成堆内存空间的不连续,从而造成大量碎片,使程序效率降低。

  可见,堆容易造成内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和内核态切换,内存申请的代价更为昂贵。所以栈在程序中应用最广泛,函数调用也利用栈来完成,调用过程中的参数、返回地址、栈基指针和局部变量等都采用栈的方式存放。所以,建议尽量使用栈,仅在分配大量或大块内存空间时使用堆。

  使用栈和堆时应避免越界发生,否则可能程序崩溃或破坏程序堆、栈结构,产生意想不到的后果。

  C语言中,未显式初始化的静态分配变量被初始化为0(算术类型)或空指针(指针类型)。由于程序加载时,BSS会被操作系统清零,所以未赋初值或初值为0的全局变量都在BSS中。BSS段仅为未初始化的静态分配变量预留位置,在目标文件中并不占据空间,这样可减少目标文件体积。但程序运行时需为变量分配内存空间,故目标文件必须记录所有未初始化的静态分配变量大小总和(通过start_bss和end_bss地址写入机器代码)。当加载器(loader)加载程序时,将为BSS段分配的内存初始化为0。在嵌入式软件中,进入main()函数之前BSS段被C运行时系统映射到初始化为全零的内存(效率较高)。

  注意,尽管均放置于BSS段,但初值为0的全局变量是强符号,而未初始化的全局变量是弱符号。若其他地方已定义同名的强符号(初值可能非0),则弱符号与之链接时不会引起重定义错误,但运行时的初值可能并非期望值(会被强符号覆盖)。因此,定义全局变量时,若只有本文件使用,则尽量使用static关键字修饰;否则需要为全局变量定义赋初值(哪怕0值),保证该变量为强符号,以便链接时发现变量名冲突,而不是被未知值覆盖。

  某些编译器将未初始化的全局变量保存在common段,链接时再将其放入BSS段。在编译阶段可通过-fno-common选项来禁止将未初始化的全局变量放入common段。

  此外,由于目标文件不含BSS段,故程序烧入存储器(Flash)后BSS段地址空间内容未知。U-Boot启动过程中,将U-Boot的Stage2代码(通常位于lib_xxxx/board.c文件)搬迁(拷贝)到SDRAM空间后必须人为添加清零BSS段的代码,而不可依赖于Stage2代码中变量定义时赋0值。

  后来该词被作为关键字引入到了IBM 709和7090/94机型上的标准汇编器FAP(Fortran Assembly Program),用于定义符号并且为该符号预留指定字数的未初始化空间块。

  在采用段式内存管理的架构中(如Intel 80x86系统),BSS段通常指用来存放程序中未初始化全局变量的一块内存区域,该段变量只有名称和大小却没有值。程序开始时由系统初始化清零。

  BSS段不包含数据,仅维护开始和结束地址,以便内存能在运行时被有效地清零。BSS所需的运行时空间由目标文件记录,但BSS并不占用目标文件内的实际空间,即BSS节段应用程序的二进制映象文件中并不存在。

  数据段通常用于存放程序中已初始化且初值不为0的全局变量和静态局部变量。数据段属于静态内存分配(静态存储区),可读可写。

  数据段保存在目标文件中(在嵌入式系统里一般固化在镜像文件中),其内容由程序初始化。例如,对于全局变量int gVar = 10,必须在目标文件数据段中保存10这个数据,然后在程序加载时复制到相应的内存。

  1) BSS段不占用物理文件尺寸,但占用内存空间;数据段占用物理文件,也占用内存空间。

  2) 当程序读取数据段的数据时,系统会出发缺页故障,从而分配相应的物理内存;当程序读取BSS段的数据时,内核会将其转到一个全零页面,不会发生缺页故障,也不会为其分配相应的物理内存。

  运行时数据段和BSS段的整个区段通常称为数据区。某些资料中“数据段”指代数据段 + BSS段 + 堆。

  代码段也称正文段或文本段,通常用于存放程序执行代码(即CPU执行的机器指令)。一般C语言执行语句都编译成机器代码保存在代码段。通常代码段是可共享的,因此频繁执行的程序只需要在内存中拥有一份拷贝即可。代码段通常属于只读,以防止其他程序意外地修改其指令(对该段的写操作将导致段错误)。某些架构也允许代码段为可写,即允许修改程序。

  代码段指令根据程序设计流程依次执行,对于顺序指令,只会执行一次(每个进程);若有反复,则需使用跳转指令;若进行递归,则需要借助栈来实现。

  代码段指令中包括操作码和操作对象(或对象地址引用)。若操作对象是立即数(具体数值),将直接包含在代码中;若是局部数据,将在栈区分配空间,然后引用该数据地址;若位于BSS段和数据段,同样引用该数据地址。

  位于虚拟地址空间的最低部分,未赋予物理地址。任何对它的引用都是非法的,用于捕捉使用空指针和小整型值指针引用内存的异常情况。

  它并不是一个单一的内存区域,而是对地址空间中受到操作系统保护而禁止用户进程访问的地址区域的总称。大多数操作系统中,极小的地址通常都是不允许访问的,如NULL。C语言将无效指针赋值为0也是出于这种考虑,因为0地址上正常情况下不会存放有效的可访问数据。

  在32位X86架构的Linux系统中,用户进程可执行程序一般从虚拟地址空间0x08048000开始加载。该加载地址由ELF文件头决定,可通过自定义链接器脚本覆盖链接器默认配置,进而修改加载地址。0x08048000以下的地址空间通常由C动态链接库、动态加载器ld.so和内核VDSO(内核提供的虚拟共享库)等占用。通过使用mmap系统调用,可访问0x08048000以下的地址空间。

  进程运行过程中,代码指令根据流程依次执行,只需访问一次(当然跳转和递归可能使代码执行多次);而数据(数据段和BSS段)通常需要访问多次,因此单独开辟空间以方便访问和节约空间。具体解释如下:

  当程序被装载后,数据和指令分别映射到两个虚存区域。数据区对于进程而言可读写,而指令区对于进程只读。两区的权限可分别设置为可读写和只读。以防止程序指令被有意或无意地改写。

  现代CPU具有极为强大的缓存(Cache)体系,程序必须尽量提高缓存命中率。指令区和数据区的分离有利于提高程序的局部性。现代CPU一般数据缓存和指令缓存分离,故程序的指令和数据分开存放有利于提高CPU缓存命中率。

  当系统中运行多个该程序的副本时,其指令相同,故内存中只须保存一份该程序的指令部分。若系统中运行数百进程,通过共享指令将节省大量空间(尤其对于有动态链接的系统)。其他只读数据如程序里的图标、图片、文本等资源也可共享。而每个副本进程的数据区域不同,它们是进程私有的。

  此外,临时数据及需要再次使用的代码在运行时放入栈区中,生命周期短。全局数据和静态数据可能在整个程序执行过程中都需要访问,因此单独存储管理。堆区由用户自由分配,以便管理。

  最近在了解线程方面的内容,总觉得对线程共享、线程全局变量、线程局部变量的处理方式有点迷糊,下面从进程和线程的角度分析了内存情况,如有不对之处,各位老鸟请留言加以指正。进程内存分析:1、栈区(stack...博文来自:yuanbinquan的专栏

  3.Linux的内存结构和管理物理内存区域Linux内核按照3:1的比率来划分虚拟内存:3GB的虚拟内存用于用户空间,1GB的内存用于内核空间。内核代码及其数据结构都必须位于这1GB的地址空间中,但是...博文来自:cxy的Linux技术专栏

  翻译自: 感谢作者,尤其一些图很漂亮,建议读者亲自读一遍英文.内...博文来自:mumumuwudi的博客

  此文也可看作是Linux下C程序的内存空间布局(虚拟地址),因为在Linux下的C编译器本质上也是一个进程,编译器再强大也得在操作系统的保护模式下运行。内存空间布局    在Linux中,进程...博文来自:程序人生

  Linux线程的内存布局在Linux的glibc中,通过pthread结构实现线程。由于线程和主进程是使用同一个虚拟地址空间,所以我们可以通过pmap-X来比较线程运行前和运行后的虚拟地址空间变化。/...博文来自:Meows的牧场

  一进程空间分布概述  对于一个进程,其空间分布如下图所示:                   程序段(Text):程序代码在内存中的映射,存放函数体的二进制代码。初始化过的数据(Data):在程序运...博文来自:鱼思故渊的专栏

  嵌入式Linux进程信息及内存布局博文来自:heliangbin87的专栏

  Unix/Linux进程在内存中的布局对于Linux操作系统之上的程序而言,其运行的进程所使用的内存地址都是虚拟地址,是MMU经过映射后的地址,我们这里所谈及的内存也是虚拟内存,而不是物理内存。如何得...博文来自:water_3700348的博客

  Linux的虚拟内存管理有几个关键概念1.每个进程有独立的虚拟地址空间,进程访问的虚拟地址并不是线.虚拟地址可通过每个进程的页表与物理地址进行映射,获得线.如果虚拟地址对应的...博文来自:啊浪的博客

  正确的理解C/C++程序的内存分区,是合格程序猿的基本要求。网络上流形两大版本内存分区,分别为:1.五大内存分区:堆、栈、全局/静态存储区、自由存储区和常量存储区。2.五大内存分区:堆、栈、全局区/静...博文来自:Dablelv的博客专栏

  在Linux系统中,以32bitx86系统来说,进程的4GB内存空间(虚拟地址空间)被划分成为两个部分------用户空间和内核空间,大小分别为0~3G,3~4G。 用户进程通常情况下,只能访问用户空...博文来自:sinat_16790541的专栏

  Windows在默认情况下,将高地址的2GB空间分配给内核(也可配置1GB),而Linux默认情况下,将高地址的1GB空间分配给内核。这些分配给内核的空间叫内和空间,用户使用剩下的空间称为用户空间。 ...博文来自:dayday_upyy

  要查看一个进程的虚拟地址空间的内存布局,需要设置阻塞。如果设置阻塞,当./a.out按下去后,程序执行的速度非常快以至于来不及查看,所以需要设置阻塞。#includeamp;amp;lt;s...博文来自:乐行僧的博客

  vector:中断向量表fixmap:内核(虚拟)空间地址固定的映射到物理内存vmalloc:非连续内存区域    vmalloc()函数用来分配物理上不连续但线性地址空间连续的高端物理内存lowme...博文来自:hello_world的博客

  从Linux系统看内存的使用情况和分布情况着实一片混乱.为此我们接着上篇部分内容继续讲...博文来自:客家族_祖仙教_小凡仙

  0.内存基本知识       我们通常称linux的内存子系统为:虚拟内存子系统(virtualmemorysystem),为何这样称谓呢?       其实这个是个很牛的设计。linux充分利用了程...博文来自:读万卷书 行万里路

  内存管理是操作系统的核心功能之一,这对于编程以及系统管理都至关重要。在接下来的叙述中我将着眼于实用方面但兼顾内部原理。这些概念都是通用的,例子大都来源于Linux以及Windows操作系统。首先来描述...博文来自:Quartzhao的专栏

  综述:   kernelimage在被bootloader或者UEFI加载后,最终会跳到kernel的入口代码处,顺便将一些参数传给内核。kernel的启动包括两个阶段,分别由两个head.S描述。第...博文来自:Joe的专栏

  近期由于项目涉及到一款基于LINUX的全息影像系统的更新问题,希望采用类似AndroidABupdata的方法更新系统,对linux内核的启动以及内存布局略微了解一下。首先,内核启动有以下几个流程:1...博文来自:SHNU_PFH的博客

  在Linux系统中,以32bitx86系统来说,进程的4GB内存空间(虚拟地址空间)被划分成为两个部分------用户空间和内核空间,大小分别为0-3G,3-4G。      用户进程通常情况下,只能...博文来自:大海蓝天的专栏

  C++内存布局(上)内存布局(下)博文来自:gaojing303504的博客

  进程的内存布局在结构上是有规律的,对于linux系统上的进程,其内存空间一般可以粗略地分为以下几大段,从高内存到低内存排列:1、内核态内存空间,其大小一般比较固定(可以编译时调整),但32位系统和64...博文来自:cztqwan的博客

  C语言程序的内存布局C语言程序的内存布局结构,包括连接过程中目标程序各个段的组成和运行过程中各个段加载的情况。C语言程序在内存中各个段的组成C语言程序连接过程中的特性和常见错误C语言程序的运行方式C语...博文来自:AderStep

  进程的内存布局如下图所示,栈是其中一块向下(低地址处)增长的内存。 栈的英文是stack,堆的英文是heap,很多人把stact翻译成堆栈,是不对的。             栈由栈帧组成。当一个函数...博文来自:chenyunlong

  堆是应用程序动态分配的内存区域。常用的做法是程序向操作系统申请一块适当大小的堆空间,然后由程序自己管理这块空间。  在Windows中,堆管理器(HeapManager)提供了一套与堆相关的API...博文来自:万里归来少年心

  这张图很好,注意其中最上面是高位地址,虽然很多个0,但是c开头的,不要看反了: 更具体的可以看这里: A.正文段。这是由cpu执行的机器指令部分。通常,正文段是可共享的,所以即使是经常执行的程序(如...博文来自:weixin_33897722的博客

  linux进程内存布局文章转载地址:内存管理是操作系统的核心之一,最近在研究内核的内存管理以及...博文来自:WSTMQ的专栏

  内存管理是操作系统的核心之一,最近在研究内核的内存管理以及C运行时库对内存的分配和管理,涉及到进程在内存的布局,在此对进程的内存布局做一下总结: 1.32位模式下的linux内存布局图上的各个部分描述...博文来自:bluestar的专栏

  内存管理是操作系统的核心之一,最近在研究内核的内存管理以及 C 运行时库对内存的分配和管理,涉及到进程在内存的布局,在此对进程的内存布局做一下总结: 1.32 位模式下的 linux 内存布局图上的各...博文来自:yangzhenzhen的专栏

  一进程空间分布概述  对于一个进程,其空间分布如下图所示:                   程序段(Text):程序代码在内存中的映射,存放函数体的二进制代码。初始化过的数据(Data):在程序运...博文来自:swartz_lubel的专栏

  BSS段(bsssegment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文BlockStartedbySymbol的简称。BSS段属于静态内存分配。数据段(datasegme...博文来自:郭龙仓的专栏

  基础知识:堆栈是一种简单的数据结构,是一种只允许在其一端进行插入或删除的线性表。允许插入或删除操作的一端称为栈顶,另一端称为栈底,对堆栈的插入和删除操作被称为入栈和出栈。有一组CPU指令可以实现对进程...博文来自:zhubo的学习笔记

  本文为转载的!!!原网址为:一进程空间分布概述  对于一个进程,其空间分布如下图所示:...博文来自:cl_linux的博客

  一般C语言的编译后执行语句都编译成机器代码,保存在.text段;已初始化的全局变量和局部静态变量都保存在.data段;未初始化的全局变量和局部静态变量一般放在一个叫.“bss”的段里heap是堆是我们...博文来自:晴天的专栏

  1.linux应用程序内存布局从低地址到高地址分别为:代码段,数据段,BSS段,堆,栈对向高内存地址生长,栈想低内存地址生长Linux的中所有的应用程序都是这个布局,每个应用程序都是从0x804800...博文来自:SYP35的专栏

  页表转换arm64在硬件体系结构上支持4级的每页大小为4K的页表转换,也支持3级的页大小64KB的页表转换。在linuxarm64中,如果页的大小为4KB,使用3级页表转换或者4级页表转换,用户空间和...博文来自:bin_linux96的专栏

  转自:上图是linux的arm的虚拟地址分布总览,我们按从低地址到高地址的顺序逐个描述,...博文来自:大海蓝天的专栏

  程序(进程)内存分布解析在多任务操作系统中的每一个进程都运行在一个属于它自己的内存沙盘中。这个沙盘就是虚拟地址空间(virtualaddressspace),在32位模式下它总是一个4GB的内存地址块...博文来自:blacet的专栏

  最近在做爬虫的时候遇到了一个问题,在用requests的session方法保持cookie的时候发现requests不能保持手动构建的cookie。起初以为requests只能自动保持由服务器返回的s...博文来自:falseen的博客

  本篇文章是根据我的上篇博客,给出的改进版,由于时间有限,仅做了一个简单的优化。相关文章:将excel导入数据库2018年4月1日,新增下载地址链接:点击打开源码下载地址十分抱歉,这个链接地址没有在这篇...博文来自:Lynn_Blog

  总结一下微信的本地图片加载有以下几个特点,也是提高用户体验的关键点 1、缩略图挨个加载,一个一个加载完毕,直到屏幕所有缩略图都加载完成 2、不等当前屏的所有缩略图加载完,迅速向下滑,滑动停止时立即加载...博文来自:lvshaorong的博客

  一、前言最近由于研究需要,要用到线性判别分析(LDA)。于是找了很多资料来看,结果发现大部分讲的都是理论知识,因此最后还是看的一知半解,后来终于找到了个英文的文档,作者由PCA引入LDA,看过后豁然开...博文来自:jnulzl的专栏

  原文地址:因为需要用,所以才翻译了这个文档。但总归赖于英语水平很有限,翻译出来的中文有可能...博文来自:ymj7150697的专栏

  那个清华镜像的版本又太低,尝试了很多办法,最终方案却很简单: 首先更新pip(非anaconda使用者请跳过这步): conda install pip conda update pip ...博文来自:数据分析之路

  扫二维码关注,获取更多技术分享 本文承接之前发布的博客《 微信支付V3微信公众号支付PHP教程/thinkPHP5公众号支付》必须阅读上篇文章后才可以阅读这篇文章。由于最近一段时间工作比较忙,...博文来自:Marswill

  强连通分量: 简言之 就是找环(每条边只走一次,两两可达) 孤立的一个点也是一个连通分量   使用tarjan算法 在嵌套的多个环中优先得到最大环( 最小环就是每个孤立点)   定义: int Ti...博文来自:九野的博客

  原文地址:反置页表作者:hilg 在分页系统中为每个进程配置一张页表,进程逻辑地址空间中的每一页,在页表中都对应有一个页表项。在现代计算机系统中通常允许一个进程的逻辑地址空间非常大,因此就有很多页表...博文来自:月光轩辕的专栏

  花了几天,终于把matlab版的人脸检测运行成功了,虽然正确率不是很高,看着各种论文上的人脸检测正确率都出奇的高,我是不怎么相信的,有的论文连基于平均脸的人脸检测正确率都能达到98%,汗啊~~  也许...博文来自:海海人生

  磁盘读写速度的关键之一:Cache     cache技术最近几年,在磁盘存储技术上,发展的非常迅速,作为高端存储,cache已经是整个存储的核心所在,就是中低端存储,也有很大的cache存在,包括...博文来自:pzk417的专栏

  jquery/js实现一个网页同时调用多个倒计时(最新的) 最近需要网页添加多个倒计时. 查阅网络,基本上都是千遍一律的不好用. 自己按需写了个.希望对大家有用. 有用请赞一个哦! //js ...博文来自:Websites

  最近做一个项目,关于用户数据和表单上传的项目,碰到了不少坑,这里总结的分享给大家,希望能够帮助大家。(小白,欢迎大家多交流)多的就不说了,直接来代码吧!!1、上传组件 说明一下,项目是基于vue框架...博文来自:woyidingshijingcheng的博客

  一、概述最近在springboot项目引入thymeleaf模板时,使用非严格标签时,运行会报错。默认thymeleaf模板对html5标签是严格检查的。二、在项目中加NekoHTML库在Maven中...博文来自:Luck_ZZ的博客

  最近想写个图书管理软件,用到了数据库,但是由于是小白,弄了好半天才把数据库搞明白。虽然网上有一些教程,但大多都是长长的文字叙述,所以想写一个图文版的连接教程并把这两天的经验记录下来。 1、首先打开ac...博文来自:u012784288的博客

http://advntravel.com/zhanyichuzhongduan/7.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有