一、当你运行你的程序通常都会访问哪些内存空间呢?

电脑自言自语道,“这个人要声明一个整数”或“这个人个方法”或“这个人要创建一个对象”

1.这些信息究竟是存在内存里的什么地方呢?

2.或者说用于描述这个整数、这些对象和方法的信息,都在哪呢?

3.这些内存的组织方式又是什么样的呢?

二、有三类不同的空间,但是其中两类与我们的关系最密切。

1.第一类存储空间:用于存储所有静态变量和常量

我们可以把它们想作不会变的变量,这是一块专门划分出来的空间,是一块比较特殊的空间,在这块特殊的空间存放着静态变量和常量,那么这特殊空间在何处呢,我们不是特别关心,总之它就是我们的特殊小可爱。

因为在程序开始运行的时候,这些东西就会被放置在内存中,我们的这些常量永远不会改变,这意味着他们并不需要被放在那些我们常常访问的内存中,他们只要呆在内存中的某个地方,然后我们知道如何访问它就可以了。

2.第二类存储空间:用于存储动态变量

1).什么是动态变量?

动态变量就是利用new申请到的变量,所以当你用new来申请一个对象的时候,比如new Goval(参数),这样就得到一个动态变量,动态变量对应的内存,也就是你用new申请到的叫做堆。

2).什么是堆?

堆就像是一大摞衣服,当你需要衣服的时候你过去说,“嘿,我需要些新衣服”然后它就给你些衣服,你穿完这些衣服就会说,“嘿,我再也不要穿这些衣服了”,然后神奇的事情就是,被你舍弃的衣服就变成了一块布,计算机知道你不再穿这些衣服了,它说,“我要把这些内存拿回来”,这就叫做垃圾回收。

垃圾回收的实质:当堆里的内存不再被需要的时候,就会被收回。

3.第三类存储空间:用于存储本地变量

这些本地变量存放在一个叫栈的地方

     什么是栈?

和堆的概念是不一样的。对栈来说,当你在某方法中访问本地变量时,或者说你在调用方法时要传递某些参数时,比如说这些参数,你实际上是把这些参数的值进行了复制,在内存中分配了另一块空间来存储它们,而时间上在栈中就会有一些空间会被自动分配给你,当你在访问本地变量后者是传递参数,或者是调用方法时,这些变量都是活跃的,而当这些变量不再活跃时,比如方法调用结束,或者遇到了右花括号时,这些变量就会消失,它们也就不能再会以任何形式被调用,然后栈就说到,“嘿,我要把这些内存空间拿回来”。

4.介绍静态变量、动态变量和本地变量

1)静态变量: 所有静态变量,或者叫特殊变量,都存储在内存中比较低的位置,也就是说,这些位置对应的数值都是比较小的,比如说在1000这个位置,注意这个1000是十六进制的而不是十进制的。

2)堆:当堆变大时它是在往下变大。往下变大是什么意思?这就是说当从2000开始的时候,你说,“嘿 堆 我需要给我的新GOval准备一些空间”它说,“好的 我给你在这里分配些内存,就在2004这个地方好啦”,然后你说,“我需要给我的新GWreck准备一些空间,它说“好的,2008这地方归你了,我会在这里这给分配空间”,所以说当堆越来越大的时候,我们就说堆在向下变大。

3)栈:栈从一些比较高的地址开始,从FFFF开始,当它分配内存时,它会向上变大。也就是说,这些地址数值会越来越小。还有一个参量用于描述本地变量、参数和动态变量,当然主要说的是动态变量。那就是它们所占用的空间大小。

4)不同变量实际上需要不同大小的存储空间,比如一个整数,int至少在C#,java占四个字节。动态变量还有一些附加内存开销,这实际上就是一些额外的内存空间,是整数和字符本身所占用空间外的一些空间,用来保存你的对象的其他信息。

三、在程序开始运行的时候,或者创建新对象的时候,到底发生了什么......

准备:

1.我们可以通过调用构造方法创建一个点,并告诉它x和y坐标,然后它就会把这个坐标保存下来,你就可以去移动这些点。

2.刚开始只是有这个类,内存尚未被分派,什么事还都没做。我们写个程序,创建点对象,并调用其对应的方法。运行程序,我们就可以知道在个过程中,计算机内存里到底发生了什么。

3.运行:

1)第一件事:调用run方法,当程序刚开始运行时run方法会被调用。

当一个方法被调用时,我们会创建这些本地变量和参数,但是run没有参数,所以不需要为参数安排空间,但它的确有两个本地变量P1和P2,但是还不包括任何信息,因为我的程序刚刚开始,还没运行到new Point这个地方。

2)第二件事:调用new便可以得到一个动态变量,这意味着它将被存储在堆里。

a.记录保存一个点的数据。构造方法的作用是将在计算机分配的空间填进数据(2,3)。

b.overhead里面是额外内存开销。

c.为什么在p1那里写1000呢?其实是我们给这个新的点分配好空间之后,该如何处理这个点呢?我们把这个点分配给P1,这里有个关键的知识点,就是计算机是怎么知道P1和它代表的所有信息都存储在那里呢?每个对象都有一个地址,实际上计算机在内部是通过对象所处的内存地址,来找到这些对象的。所以当我调用new的时候,就会在堆中申请一块空间。然后把这段空间赋值给p1,到底是什么东西被赋值了呢?实际上是把P1的内存地址进行了赋值,确切的讲是起始地址。通过这个起始地址可以找到P1包含的所有数据,这些数据就被存储在stack(1000)里,这里的1000是内存地址1000。

3)第三件事:新建一个新点,需要从堆那里要点内存。

堆说,“1008之前的地址已经分配出去了,那我就接着给你分配一块能放得下一个点的空间,用来保存你的实例变量。

然后计算机就说好,分配我一个空间,然后调用构造方法,将点的数据填入存储单元,再将起始地址100C赋值给p2。px、py是属于p1的实例变量,后来分配的px、py是属于p2的实例变量。

4)第四件事:神奇的事件。调用一个方法,例如调用p1.move。

a.当我们调用这个方法时,我们会有一些参数和本地变量。也就是说我们要在栈上分配内存才能进行方法的调用。所以当我们调用方法时所发生的就是,“嘿,p1我要把你移动一下偏移(10,11)这么多”。那再内存中发生了什么事呢?内存中发生的事情就是:我们会创建一个新的“栈帧”,当你调用一个方法的时候,调用方法的方法,或者说原先运行的方法就会被挂起。内部的情况是这样的,我们在栈上分配内存空间,所以我们管它叫栈帧,它存储了调用这个方法所需要的信息。什么信息,首先是方法的调用,额外内存开销,需要存储所有传进来的参数。

b.关于this,有一个隐藏参数,当我针对某特定对象调用方法后,我如何得知这个方法要调用的对象是哪个?当你对一个对象调用方法的时候,在所谓的内存开销之后,紧接着放在栈上的内容,实际上是指向这个对象的指针;我们把它叫做this指针。this是对象访问自己的一种方式。它需要知道自己在内存的某个地方。

c.很奇怪,为什么对象需要知道自己呆在什么地方呢?

因为当我们写一个方法的时候,我们并没有将这些方法跟已经创建的某些特定对象进行关联。如果我创建一个特定的对象(如p1),然后对其调用那个方法,那个方法得知道,“嘿,你让我改变px py值,你说的是那个px py值”,这个时候,this就起作用了。

this说:“我知道这个方法对应对象在内存中的位置。”这样无论你在程序里进行什么样的操作,都可以通过this指定你要访问的对象。

进行方法调用的时候,首先要知道这个方法所对应的那个特定的对象的地址。我们针对p1进行调用,p1放在1000这个位置。所以p1就是1000,指针this指的值就是1000.接下来逆序存放传入的参数。传入参数值,这些是传入参数的副本。

5)第五件事:现来看看调用move方法时会怎样?现在栈里面已经存储了move的本地变量,和对象对应的指针地址。

a.第五步执行的是px加10,但是是那个px呢?我们顺着this指针找到的那个px。

如何找?

b.去this存储的地址找。于是它到达1000位置那里,读取额外内存开销信息,它就知道px相对起始位置1000的位置。然后它继续说“嘿已经找到了,它的值是2,我在它上面加上10变成12”。

6)第六件事:很有趣的事情。当栈内变量不再活跃时,它们就会被删除。

a.这个时候计算机会自动跑过来说,“嘿,这块变量,这块内存,再也不会用到,我要把它收回。”所以栈上这部分的内存,就是与move方法相关的栈帧。这些就是调用move分配的内存。也就是说所有为move分配的内存被机器自动的收回。这就叫做"栈里弹出"。想象一下,当栈顶的东西用完后,把它从栈顶上弹出去,然后它就没有了。

b.如果再次调用move方法?相关的信息又会重新放在栈帧上,但执行过一次move之后就不需要了。

注意:构造方法和其他方法的区别,构造方法不用this指针。

(二)学习C#之内存管理的更多相关文章

  1. linux kernel学习笔记-5内存管理_转

    void * kmalloc(size_t size, gfp_t gfp_mask); kmalloc()第一个参数是要分配的块的大小,第一个参数为分配标志,用于控制kmalloc()的行为. km ...

  2. XV6学习笔记(2) :内存管理

    XV6学习笔记(2) :内存管理 在学习笔记1中,完成了对于pc启动和加载的过程.目前已经可以开始在c语言代码中运行了,而当前已经开启了分页模式,不过是两个4mb的大的内存页,而没有开启小的内存页.接 ...

  3. linux学习的任督二脉-进程调度和内存管理

    转自 宋宝华老师的博客原文:https://blog.csdn.net/21cnbao/article/details/77505330 内功心法 学习或遇到问题时,反过来主动思考如果我是设计者,我会 ...

  4. COCOS学习笔记--Cocod2dx内存管理(三)-Coco2d-x内存执行原理

    通过上两篇博客.我们对Cocos引用计数和Ref类.PoolManager类以及AutoreleasePool类已有所了解,那么接下来就通过举栗子来进一步看看Coco2d-x内存执行原理是如何的. / ...

  5. 嵌入式linux学习笔记1—内存管理MMU之虚拟地址到物理地址的转化

    一.内存管理基本知识 1.S3C2440最多会用到两级页表:以段的方式进行转换时只用到一级页表,以页的方式进行转换时用到两级页表.页的大小有三种:大页(64KB),小页(4KB),极小页(1KB).条 ...

  6. Linux内核学习笔记——内核内存管理方式

    一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...

  7. ios学习笔记之内存管理

    一,内存管理类型定义      1,基本类型  任何C的类型,eg:      int,short,char,long,long long,struct,enum,union等属于基本类型或结构体   ...

  8. cocos2d-x学习之自动内存管理

    一.自动内存管理 1)概述 C++语言默认是没有提供自动内存管理的.使用者需要自己分配,自己释放.在cocos2d-x里提供了一个自动内存管理的方案.主要是通过CCObject来提供的,用户只要继承了 ...

  9. 【IOS学习基础】内存管理

    1.内存几大区域 1> 栈区:局部变量(基本数据类型.指针变量). 2> 堆区:程序运行的过程中动态分配的存储空间(创建的对象). 3> BSS段:没有初始化的全局变量和静态变量. ...

随机推荐

  1. Oracle外部表的使用

    外部表可以像其它表一样,用select语句作查询.但不能做DML操作,不能建index,不接受约束.这是因为它不是以段的形式存于数据库中,只是以数据字典构造存在,指向一个或多个操作系统文件. 外部表的 ...

  2. MongoDB 日期 插入时少8小时

    存储在mongodb中的时间是标准时间UTC +0:00  而咱们中国的失去是+8.00 . C#的驱动支持一个特性,将实体的时间属性上添加上这个特性并指时区就可以了.例如:[BsonDateTime ...

  3. 录制游戏视频——fraps

    http://pcedu.pconline.com.cn/341/3417224.html

  4. EXTJS 4.2 资料 控件之textfield文本框加事件的用法

    { xtype: "textfield", width: 100, id: "txtGroupName", name: "txtGroupName&q ...

  5. iOS 获取手机的型号,系统版本,软件名称,软件版本

    转载自:http://www.2cto.com/kf/201210/162333.html   网上搜索出来的,记录下来以后使用方便: [java]//手机序列号      NSString* ide ...

  6. java 构造函数

    1.public className(){}. 2.名称与类名相同,无返回值,无返回类型,void也不行.(就是上边的形式,除了可以有参数). 3.有0个或多个参数. 4.每个类都至少有一个const ...

  7. python 记录日志logging

    在项目开发中,往往要记录日志文件.用python记录日志有两种方式: 1.利用python 自带的logging库,例如: # -*- coding: utf-8 -*- import osimpor ...

  8. uc/os初始化

        操作系统初始化函数OS_INIT是操作系统在开始运行的最初,对全局变量.任务控制块.就绪表.事件及消息队列等重要数据结构进行的初始化操作,并创建空闲任务.统计任务等系统任务.该函数必须在创建用 ...

  9. bzoj 2876: [Noi2012]骑行川藏 拉格朗日数乘

    2876: [Noi2012]骑行川藏 Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 1033  Solved: ...

  10. [转载]WCF序列化65536大小限制的问题

    错误: The formatter threw an exception while trying to deserialize the message: There was an error whi ...