内存的管理艺术(基于C语言)1

内存的管理艺术(基于C语言)1

基于朱有鹏的C语言高级专题1,内存管理---可变数据的管理


1、程序运行为什么需要内存?

(1)计算机程序运行的目的:

     计算机为什么需要编程?编程已经写了很多程序了,为什么还需要另外的写程序,计算机有这个新的程序到底是为了什么?

     程序的目的是为了去运行,程序的运行是为了得到一定的结果。为什么需要另外写程序,因为需要得到不同的结果,计算机就是用来计算的,所有的程序其实都是在做计算,计算就是在计算数据。所以我们计算机程序里面很重要的部分就是数据。

     计算机程序 代码 数据    计算机程序运行得到的一个结果

也就是说代码加数据经过运行后 =  结果

 从宏观上来理解:代码就是动作,数据就是被计算的东西,关联就是代码就是加工数据的东西。

 结论:

程序运行的目的不外乎2个:结果和过程   

函数就是程序得到的结果,返回值为void的值的话,那么就是只在乎过程的程序。

用函数来类比:函数的形参就是待加工的数据(函数内还需要一些临时数据,就是局部的变量)函数的本体就是代码,函数体的执行的过程就是过程。


(2)程序运行的过程

计算机程序的运行过程,其实就是程序中很多歌函数运行的过程,程序是由很多个函数组成的,程序的本质是函数,函数的本质是加工数据的动作。


2、冯诺依曼结构和哈弗结构:

(1)概念

冯诺依曼结构是:数据和代码放在一起

哈弗结构是:数据和代码分开存在

(他们之间没有本质的区别)? 

现在的电脑使用的虽然是冯诺依曼结构,但是使用了很多的cache来把数据和代码分开的读取和发送,

其实就是使用哈弗结构的思想来编写代码。

 

哈弗结构效率比较高但是设计比较复杂

冯诺依曼结构效率比较慢但是设计简单。


(2)结合分析

什么是代码:函数

什么是数据:全局变量,局部变量

 

linux系统上,运行应用程序的时候,这时候所有的应用程序的代码和数据都在DRAM上面的。所以这种结构就是冯诺依曼结构。

 

比如在单片机中,我们把程序的代码FLASH中(NORFLASH),然后程序在FLASH中原地运行。程序中所涉及到的数据(全局变量、局部变量中)不能放在FLASH中,必须放在RAM中。(SRAM)这就是我们所说的哈弗结构。

 

我们写程序的时候最重要的是内存,因为内存的这个玩意不是只读的,所以不安全,FLASH是用来存放代码的,但是他是只读的,所以很安全。


3、动态内存DRAM和静态内存SRAM

DRAM是动态的内存,SRAM是静态内存

静态的内存是指在程序开始运行时由编译器分配的内存,他的分配是在程序开始编译完成的,不占用CPU资源。

程序中的各种变量,在编译时系统已经为其分配了所需的内存空间,当该变量在作用域使用完毕时,系统会自动释放所占用的内存空间。

类似的有数组

动态内存:

用户无法确定空间大小,或者空间太大,栈上无法分配时,会采用动态内存分配。

 

区别:

1、静态内存分配在编译时完成,不占用CPU资源,动态内存分配在运行时,分配与释放都占用CPU资源。

2、静态内存在栈(stack)上分配;动态内存分配在运行时,分配与释放都占用CPU资源。

3、动态内存分配需要指针和引用类型支持,静态不需要。

4、静态内存分配是按计划分配,由编译器负责,动态内存分配是按需分配,由程序员负责。

程序的侧重点最重要的是数据,而代码是死的东西,写程序你能把数据把握好就可以了。



附带上别人的理解:

http://blog.csdn.net/hairetz/article/details/4141043/

一个由C/C++编译的程序占用的内存分为以下几个部分。

1、栈区域:stack

由编译器自动分配释放,存放函数的参数值,局部变量的值等,其操作方式类似于数据结构中的栈。

 

2、堆区(heap

  一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收,分配方式类似于链表。

3、全局区:(static

全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量的存储是放在一块的,初始化的,静态变量和全局变量在一块区域的,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后由系统释放。

 

4、文字常量区:

常量字符串就是放在这里的,程序结束后由系统释放

 

5、程序代码区:

存放函数体的二进制代码


 从图中可以栈和堆得分布的方式是截然不同,一般程序员自己申请的堆是慢慢的向上增长的,而且大小

是不定的。



总结:为什么需要内存?

因为内存是用来存储可变的数据,只要是数据的话,应该都是可变的,不可变的是代码。

数据在程序中表现为全局变量、局部变量等,在GCC中其实常量也是存储在内存当中的。

单片机中大部分常量是存储在FALSH中的,也就是在代码段里面的。对我们写程序来说是非常重要,对程序运行更是本质相关。

所以内存对程序来说几乎是本质的需求,越简单的程序需要越少的内存,而越庞大的越复杂的内存需要更多的内存,内存管理是我们写程序时很重要的话题。我们以前学过的很多东西,很多编程的关键其实都是为了内存。

比如说数据结构和算法,数据结构是研究数据如何组织的,数据是放在内存当中的,和算法是为了用更优秀更有效的方法来加工数据既然跟数据有关就离不开内存。

 

深入思考:如何管理内存

对于计算机来说,内存容量越大则可能性越大,所以说大家都希望自己的电脑内存更大。

我们写程序时,如何管理内存就成为了很大的问题,如果管理不善,可能会造成程序运行消耗过多的内存,这样迟早内存都被你这个程序吃光了。当没有内存可用的时,程序就会奔溃,所以内存对程序来说是一种资源,所以管理内存,对于程序来说,是一个重要的技术和话题。

 

先从操作系统的角度来说:操作系统掌握所有的硬件内存,因为内存很大,所以操作系统把内存分为一个一个的页面,(其实就是一块一般是4KB,)然后以页面为单位来管理。

页面内用更细小的方式以字节为单位管理。

操作系统内存管理的原理非常麻烦,非常复杂,非常不人性话,那么对于我们这些使用操作系统的人来说,其实不需要了解这些细节,操作系统给我们提供了内存管理的一些接口,

我们只需要用API即可管理内存,

比如在C语言中使用malloc   free这些接口来管理内存。

 

没有操作系统的时候,内存就需要我们自己来管理了,没有操作系统也就是裸机程序时,程序需要直接操作内存,编程者需要自己计算内存的使用和安排,如果编程者不小心把内存用错了,错误的结果需要自己承担。我们在用裸机程序的时候是非常麻烦的

 

再从语言的角度来讲:

不同的语言提供了不同的操作内存的接口,比如汇编,根本没有任何的内存管理,内存管理全靠程序员自己,汇编中操作内存时直接使用内存地址,比如说我们直接操作内存地址。

比如C语言中编译器帮我们管理直接内存地址,我们都是通过编译器提供的变量名等访问内存的,如果在操作系统,如果需要大块的内存,可以使用APImalloc  free)来访问内存。

裸机需要自己定义数组等解决。

C++语言:C++语言对内存的使用进一步封装,我们可以用new来创建对象,其实就是为对象分配内存,然后使用完了之后用delete来删除对象(其实就是释放内存)所以C++语言对内存的管理比C更加高级一些。但是C++中内存的管理靠程序员自己来做,如果程序员new了一个对象,但是用完了忘记delete,就会造成这个对象占用的内存不能释放,这就是内存泄露。

 

JAVAC#语言:这些语言不直接操作内存,而是通过虚拟机来操作内存。这样虚拟机作为我们程序员的代理;来帮我们处理内存的释放工作。如果我们的程序使用了内存,使用完后忘记释放,则虚拟机会帮我释放掉这些内存。听起来视乎C#JAVAC/C++有优势,但是其实他这个虚拟机回收内存是需要付出一定的代价的。所以说语言没有好坏,只有适应不适应,当我们程序对性能十分在乎的时候(比如操作系统内核)就会使用C/C++语言,当我们对开发程序的速度非常在乎的时候,就会用JAVA/C#语言。