内存
文章平均质量分 84
JayerZhou
这个作者很懒,什么都没留下…
展开
-
C语言变量的存储类别和生存期
C语言变量的存储类别和生存期我们知道,变量是有数据类型的,用来说明他占用多大的内存空间,可以进行什么操作。除了数据类型,变量还有一个属性,称为“存储类别”。存储类别就是变量在内存中的存放区域。在进程的地址空间中,常量区、全局数据区和栈区都可以用来存放变量的值。常量区和全局数据区的内存在程序启动时就已经由操作系统分配好,占用的空间固定,程序运行期间不再改变,程序运行结束后才由操作系统释放;他可以存放全局变量、静态变量、一般常量和字符串常量。栈区的内存在程序运行期间由系统根据需要来分配(使用到变量才分配原创 2021-12-17 17:25:16 · 1804 阅读 · 1 评论 -
内存泄露(以c语言为例)
内存泄露使用malloc()、calloc()、realloc()动态分配的内存,如果没有指针指向他,就无法进行任何操作,这段内存会一直被程序占用,知道程序运行结束由操作系统回收。请看下面代码:#include <stdio.h>#include <stdlib.h>int main(){ char *p = (char*)malloc(100 * sizeof(char)); p = (char*)malloc(50 * sizeof(char));原创 2021-12-17 14:53:06 · 4474 阅读 · 1 评论 -
C语言野指针以及非法内存操作
C语言野指针以及非法内存操作如果一个指针指向的内存没有访问权限,或者指向一块已经释放掉的内存,那么就无法对该指针进行操作,这样的指针称为野指针(Wild Pointer)。指向没有访问权限的内存请看下面的代码:#include <stdio.h>int main(){ char *str; gets(str); puts(str); return 0;}在GCC下运行,输入一个字符串后会提示段错误(Segment Fault)。在VS下运行,输入一原创 2021-12-17 14:30:40 · 2499 阅读 · 1 评论 -
malloc函数背后的实现原理 -- 内存池
malloc函数背后的实现原理 – 内存池相对于栈而言,堆这片内存面临着一个稍微复杂的行为模式:在任意时刻,程序可能发出请求,要么申请一段内存,要么释放一段已经申请过的内存,而且申请的大小从几个字节到几个GB都有可能,我们不能假设程序一次申请多少堆空间,因此,堆的管理显得较为复杂。那么,使用malloc()在堆上分配内存到底是如何实现的呢?一种做法是把malloc()的内存管理交给系统内核去做,既然内核管理着进程的地址空间,那么如果它提供一个系统调用,可以让malloc()使用这个系统调用去申请内存,原创 2021-12-17 13:30:10 · 355 阅读 · 0 评论 -
C语言动态内存分配
C语言动态内存分配在进程的地址空间中,代码区、常量区、全局数据区的内存在程序启动时就已经分配好了,他们大小固定,不能由程序员分配和释放,只能等到程序运行结束由操作系统回收。这称为静态内存分配。栈区和堆区的内存在程序运行期间可以根据实际需求来分配和释放,不用在程序刚启动时就备足所有内存。这称为动态内存分配。使用静态内存的优点是速度快,省区了向操作系统申请内存的时间,缺点就是不灵活,缺乏表现力,例如不能控制数据的作用范围,不能使用较大的内存。而使用动态内存可以让程序对内存的管理更加灵活和高效,需要内存就立原创 2021-12-16 11:54:13 · 221 阅读 · 0 评论 -
栈溢出攻击的原理
栈溢出攻击的原理先看一个例子:#include <stdio.h>int main(){ char str[10] = {0}; gets(str); printf("str: %s\n", str); return 0;}在main()函数内部定义一个数组,并通过get()为他赋值。在VS2010 Debug模式下运行程序,当输入的字符不超过10个时,可以正确输出。但是当输入的字符过多时,就会出现运行时错误。例如输入“012345678901234原创 2021-12-15 17:17:04 · 1868 阅读 · 0 评论 -
一个实例深入了解函数进栈出栈过程
一个实例深入了解函数进栈出栈过程我们之前提到了函数的活动记录,这里我们就以VS2010 Debug模式为例来深入分析一下。先看一段代码:void func(int a, int b){ int p =12, q = 345;}int main(){ func(90, 26); return 0;}函数使用默认的调用惯例cdecl,即参数从右到左入栈,由调用方负责将参数出栈。函数的进栈出栈过程如下图所示:函数进栈以下几步为函数进栈过程:main()是主函数,原创 2021-12-09 17:50:22 · 3140 阅读 · 2 评论 -
一个函数在栈上的形式、函数的调用惯例
一个函数在栈上的形式、函数的调用惯例函数的调用和栈是分不开的,没有栈就没有函数调用,我们来了解一下函数在栈上是如何被调用的。栈帧/活动记录当函数发生调用时,会将函数运行需要的信息全部压入栈中,这常常被称为栈帧(Stack Frame)或活动记录(Activate Record)。活动记录一般包括以下几个方面的内容:1)函数的返回地址,也就是函数执行完成后从哪里开始继续执行后面的代码。例如:int a, b, c;func(1, 2);c = a + b;站在C语言的角度看,func()函数原创 2021-12-09 13:50:48 · 969 阅读 · 0 评论 -
栈(Stack)、栈溢出问题
栈(Stack)、栈溢出问题在Linux、Windows下C语言内存布局(内存模型)中曾经说到程序的虚拟地址空间分为多个区域。栈(Stack)可以存放函数参数、局部变量、局部数组等作用范围在函数内部的数据,他的用途就是完成函数的调用。栈内存由系统自动分配和释放:发生函数调用时就为函数运行时用到的数据分配内存,函数调用结束后就将之前分配的内存全部销毁。所以局部变量、参数只在当前函数中有效,不能传递到函数外部。栈的概念在计算机中,栈可以理解为一个特殊的容器,用户可以将数据依次放入栈中,然后再将数据按照相原创 2021-12-08 13:16:04 · 1134 阅读 · 0 评论 -
用户模式和内核模式
用户模式和内核模式首先我们要解释一个概念–进程(Process)。简单来说,一个可执行程序就是一个进程,前面我们使用C语言编译生成的程序,运行后就是一个进程。进程最显著的特点就是拥有独立的地址空间。严格来说,程序是存储在磁盘上的一个文件,是指令和数据的集合,是一个静态的概念;进程是程序加载到内存运行后的一些活动,是一个动态的概念。前面我们在说到地址空间时,一直说“程序的地址空间”,这其实是不严谨的,应该说“进程的地址空间”。一个进程对应一个地址空间,而一个程序可能会创建多个进程。内核模式和用户模式原创 2021-11-25 15:07:06 · 758 阅读 · 0 评论 -
Linux、Windows下C语言内存布局(内存模型)
Linux、Windows下C语言内存布局(内存模型)在虚拟地址空间及编译模式中提到,虚拟地址空间在32位环境下大小为4GB,在64位环境下大小为256TB,那么,一个C语言程序的内存在整个地址空间中是如何分布的呢?数据在哪里?代码在哪里?为什么要这样分布?内核空间和用户空间对于32位环境,理论上程序可以拥有4GB的独立空间,我们在C语言中使用到的变量、函数、字符串等都会对应内存中的一块区域。但是,在这4GB的地址空间中,要拿出一部分给操作系统内核使用,应用程序无法直接访问这一段内存,这一部分内存地原创 2021-11-23 15:56:06 · 3299 阅读 · 0 评论 -
MMU部件以及对内存权限的控制
MMU部件以及对内存权限的控制通过页表完成虚拟地址和物理地址映射时,要经过多次转换,还要进行计算,如果由操作系统来完成这项工作,那将会成倍降低程序性能,得不偿失,所以这种方式是不现实的。MMU在CPU内部,有一个部件叫做MMU(Memory Management Unit,内存管理单元),由它来负责将虚拟地址映射为物理地址,如下图所示:在页映射模式下,CPU发出的是虚拟地址,也就是我们在程序中看到的地址,这个地址会先交给MMU,经过MMU的转换以后才能变成物理地址。即便是这样,MMU也要访问好几原创 2021-11-23 11:19:07 · 791 阅读 · 0 评论 -
内存分页,完成虚拟地址的映射。页表与页目录又表示什么?
内存分页,完成虚拟地址的映射。页表与页目录又表示什么?虚拟地址与物理地址转换关于虚拟地址和物理地址映射有很多思路,我们可以假设以程序为单位,把一段与程序运行所需要的同等大小的虚拟空间映射到某段物理空间。例如程序A需要10MB内存,虚拟地址的范围是从0X00000000到0X00A00000,假设他被映射到一段同等大小的物理内存,地址范围从0X00100000到0X00B00000,即从虚拟空间中的每一个字节对应于物理空间中每一个字节。程序运行时,他们的对应关系如下图所示:[外链图片转存失败,源站可原创 2021-11-21 16:51:16 · 1398 阅读 · 0 评论 -
内存对齐,提高寻址效率
内存对齐,提高寻址效率计算机内存是以字节(Byte)为单位划分的,理论上CPU可以访问任意编号的字节,但实际情况并非如此。CPU通过地址总线来访问内存,一次能处理几个字节的数据,就命令地址总线读取几个字节的数据。例如,32位的CPU一次能处理4个字节的数据,那么每次就从内存读取4个字节的数据。少了浪费主频,多了也没有用。64位的处理器也是这个道理,每次读取8个字节。以32位CPU位例,实际寻址的步长为4个字节,也就是只对编号为4的倍数内存寻址,例如0、4、8、12、1000等,而不会对编号1、3、11原创 2021-11-08 20:00:52 · 660 阅读 · 1 评论 -
虚拟地址空间、CPU的数据处理能力、编译模式
虚拟地址空间、CPU的数据处理能力、编译模式所谓虚拟地址空间,就是程序可使用的虚拟地址有效范围。虚拟地址和物理地址的映射关系由操作系统决定,相应的,虚拟地址空间的大小也由操作系统决定,但还会收到编译模式的影响。我们先说说CPU,再看看编译模式,来了解编译器是如何配合CPU来提高程序运行速度的。CPU的数据处理能力CPU是计算机的核心,决定了计算机的数据处理能力和寻址能力,也即决定了计算机的性能。CPU一次(一个时钟内)能处理数据的大小由寄存器的位数和数据总线的宽度(也就是由多少根数据总线)决定,我们原创 2021-11-06 16:09:44 · 727 阅读 · 0 评论 -
虚拟内存是什么?我们在程序中看到的内存地址大多是假的?使用虚拟地址的高处是什么?
虚拟内存是什么?我们在程序中看到的内存地址大多是假的?使用虚拟地址的高处是什么?在C语言中,指针变量的值就是一个内存地址,&运算符的一个作用也是取变量的地址,如:#include <stdio.h>#include <stdlib.h>int a = 1, b = 255;int main(){ int *pa = &a; printf("pa = %#X, &b = %#X\n", pa, &b); system("原创 2021-11-04 20:08:15 · 223 阅读 · 0 评论 -
初识CPU,一个程序在计算机中是如何运行的
初识CPU,一个程序在计算机中是如何运行的初识CPU我们知道,程序是保存在硬盘中的,如果想要运行程序,就要将他载入内存,而CPU也被设计为只能从内存中读取数据和指令。对于CPU来说,内存只不过是个存放指令和数据的地方,并不能在内存中完成计算功能。如果我们要计算 a = b + c,必须将a、b、c都读取到CPU中才能进行加法运算。CPU是个复杂的计算机部件,内部又包含了很多小零件,如图:运算单元是CPU的大脑,负责加减乘除、比较、位移等运算工作,每种运算都有对应的电路支持,速度很快。寄存器(R原创 2021-11-04 16:06:37 · 748 阅读 · 0 评论