内存原理介绍

1.       .Net应用程序中的内存

1.1.Net内存类型

Windows使用一个系统:虚拟寻址系统。这个系统的作用是将程序可用的内存地址映射到硬件内存中的实际地址上。其实际结果是在32位的Windows操作系统中,每个进程都可以使用4GB的内存,当然,64位机这个数字就更大了,在这4GB的内存中存储着可执行代码、代码加载的DLL和程序运行的所有变量,这4GB的内存成为虚拟地址空间或虚拟内存。在.Net中要使用多种类型的内存,包括:堆栈、非托管堆和托管堆。

C#将数据分为2种:值数据类型和引用数据类型,值数据类型存储在堆栈中,引用类型存储在内存的托管堆中。

内存格局通常分为4个区:

全局数据区:存放全局变量,静态数据,常量;代码区:存放所有的程序代码;栈区:存放为运行而分配的局部变量,参数,返回数据,返回地址等;堆区:即自由存储区

堆栈

堆栈用于存储应用程序执行过程中的局部变量、方法参数、返回值和其他临时值。堆栈按照每个线程进行分配,并作为每个线程完成其工作的一个暂存区。垃圾收集器并不负责清理堆栈,因为为方法调用预留的堆栈会在方法返回时被自动清理。但是请注意,垃圾收集器知道堆栈上存储的对象的引用。当对象在一种方法中被实例化时,该对象的引用(32位或64位整型值,取决于平台类型)将保留在堆栈中,而对象自己却存储在托管堆中,并在变量超出范围时被垃圾收集器收集。

堆栈实际上是向下填充,即由高内存地址向低内存地址填充,堆栈的工作方式是先分配内存的变量后释放即先进后出原则,堆栈中的变量是从下向上释放,这样就保证了堆栈中先进后出的规则不与变量的生命周期起冲突,性能非常高,但是对于所有的变量来说不太灵活,而且变量的生命周期必须嵌套。

非托管堆

非托管堆存储引用类型如类、对象、并受垃圾收集器的控制和管理。用于运行时数据结构、方法表、Microsoft中间语言(MSIL)、JITed代码等。非托管代码根据对象的实例化方式将其分配在非托管堆或堆栈上。托管代码可通过调用非托管的Win32 API或实例化COM对象来直接分配非托管堆内存。CLR出于自身的数据结构和代码原因广泛地使用非托管堆。

托管堆

托管堆是用于分配托管对象的区域,同时也是垃圾收集器的域。CLR使用分代压缩垃圾收集器。垃圾收集器之所以称为分代式,是由于它将垃圾收集后保留下来的对象按生存时间进行划分,这样做有助于提高性能。所有版本的.Net Framework都采用三代分代方法:第0代、第1代、第2代(从年轻代到年老代)。垃圾收集器之所以称为压缩式,是因为它将对象重新定位于托管堆上,从而能够消除漏洞并保持可用内存的连续性。移动大型对象的开销很高,因为垃圾收集器将这些大型对象分配在独立的且不会压缩的大型对象堆上。

堆是从下往上分配,所以自由的空间都在已用空间的上面。

1.2 对象的生命周期

概述

1)  .net对象是被分配到一块叫做托管堆(managed Heap)的内存区域上

2)  New一个对象,返回的是一个指向堆上的引用,而不是真正的对象本身,这个对象保存在栈上

3)  对象管理法则:1、new后不用再管。2、如果托管堆上没有足够的内存,就会进行垃圾回收。

4)  应用程序根:根就是一个存储位置,保存着对堆上一个对象的引用,可以是以下几种类别:

(a)       全局对象的引用(虽然在C#不允许,但是CIL的确允许分配全局对象)

(b)       静态对象/静态字段的引用

(c)       应用程序的代码库的局部对象的引用

(d)       传递进一个方法的对象参数的引用

(e)       等待被终结的对象的引用

(f)        任何引用对象的CPU寄存器

工作原理

在一次垃圾回收过程中,运行库将检查托管堆上的对象,判断应用程序是否仍然可达到它们,即是否有根的。为此,CLR将建立一个对象图,代表堆上可达的每一个对象。没有在对象图中的即为被标记为终结的对象,会从内存中清除,然后,调整可达的对象在内存上的位置,组成一个无冗余并且压缩过的堆。

在堆栈中,一旦变量超出使用范围,其使用的内存空间会被其他变量重新使用,这时其空间中被存储的值将被其他变量覆盖而不复存在,但有时候我们希望这些值仍然存在,这就需要托管堆来实现。

class1 object1;

object1=new class1();

第一句定义了一个class1的引用,实质上只是在堆栈中分配一个4个字节的空间,它将存放后来实例化对象在托管堆中的地址,在windows中这需要4个字节来表示内存地址。

第二句实例化object1对象,实际上是在托管堆中开辟一个内存空间来存储类class1的一个具体的对象,假设这个对象需要36个字节,那么object1指向的实际上是在托管堆一个大小为36个字节的连续内存空间开始的地址。由此可以看出在C#编译器中为什么不允许使用未实例化的对象,因为这个对象在托管堆中还不存在,当对象不再使用时,这个被存储在堆栈中的引用变量将被删除,但是从上述机制可以看出,在托管堆中这个引用指向的对象仍然存在,其空间何时被释放取决垃圾收集器而不是引用变量失去作用域时。

工作方式

进程中每个线程都有自己的堆栈,这是一段线程创建时保留下的地址区域。我们的“栈内存”即再次,至于“堆”内存,个人认为在未用new定义时,堆应该就是未“保留”未“提交”的自由空间,new的功能是在这些自由空间中保留出一个地址范围

栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有FIFO。FIFO的特性,在编译的时候可以指定需要的Stack的大小。在编程中,例如C/C++中,所有的局部变量都是从栈中分配内存空间,实际上也不是什么分配,只是从栈顶向上用就行,在退出函数的时候,只是修改栈指针就可以把栈中的内容销毁,所以速度最快。

堆(Heap)是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程,在C/C++分别用malloc/New请求分配Heap,用free/delete销毁内存。由于从操作系统管理的内存分配所以在分配和销毁的时候要占用时间,所以用堆的效率低的多,但是堆的好处是可以做的很大,C/C++堆分配的Heap是不初始化的。

在Java中除了简单类型(int,char等)都是在堆中分配内存,这也是程序慢的一个主要原因。但是跟C/C++不同,Java中分配的Heap内存是自动初始化的。在Java中所有的对象(包括int的wrapper Integer)都是在堆中分配,但是这个对象的引用却是在Stack中分配。也就是说在建立一个对象时从2个地方都分配内存,在Heap中分配的内存实际建立这个对象,而在Stack中分配的内存只是一个指向这个堆对象的指针(引用)而已。

1.3垃圾回收概念(GC)引入

在使用电脑的过程中大家可能都有过这种经验:电脑用久了以后程序运行会变得越来越慢,其中一个重要原因就是系统中存在大量内存碎片,就是因为程序反复在堆栈中创建和释入变量,久而久之可用变量在内存中将不再是连续的内存空间,为了寻址这些变量将会增加系统开销。在.net中这种情形将得到很大改善,这是因为垃圾收集器的工作,垃圾收集器将会压缩托管堆的内存空间,保证可用变量在一个连续的内存空间内,同时将堆栈中引用变量中的地址修改为新地址,这将会带来额外的系统开销,但是,其带来的好处将会抵消这种影响,而另外一个好处是,程序员将不再花上大量的心思在内存泄漏问题上。

说明,在C#程序中不仅仅只有引用类型的变量,仍然也存在值类型和其他托管堆不能管理的对象,例如文件句柄、网络连接和数据库连接,这些变量的释放仍需要程序员通过析构函数或IDispose接口来做。

1.4参考资料

http://www.tudou.com/home/diary_v9913437.html

http://www.cnblogs.com/skywithcloud/archive/2011/08/12/2136789.html

http://msdn.microsoft.com/zh-cn/magazine/cc163491.aspx

http://blog.csdn.net/directionofear/article/details/8034133

内存分析_.Net内存原理介绍的更多相关文章

  1. 内存分析_.Net垃圾回收介绍

    垃圾回收 1.       .Net垃圾回收中涉及的名称 1.1.什么是代? 垃圾回收器为了提升性能使用了代的机制,共分为三代(Gen0.Gen1.Gen2).GC工作机制基于以下假设, 1)  对象 ...

  2. Linux 内存分析工具的命令大全介绍

    在Linux系统经常被用作服务器系统.当服务器内存吃紧的时候,free命令是我们最常使用的内存分析工具. free使用介绍# free命令可以显示Linux系统中空闲的.已用的物理内存及swap内存, ...

  3. 『Numpy』内存分析_高级切片和内存数据解析

    在计算机中,没有任何数据类型是固定的,完全取决于如何看待这片数据的内存区域. 在numpy.ndarray.view中,提供对内存区域不同的切割方式,来完成数据类型的转换,而无须要对数据进行额外的co ...

  4. 『Numpy』内存分析_利用共享内存创建数组

    引.内存探究常用函数 id(),查询对象标识,通常返回的是对象的地址 sys.getsizeof(),返回的是 这个对象所占用的空间大小,对于数组来说,除了数组中每个值占用空间外,数组对象还会存储数组 ...

  5. Linux 内存分析工具——free命令

    在Linux系统经常被用作服务器系统.当服务器内存吃紧的时候,free命令是我们最常使用的内存分析工具. free使用介绍 free命令可以显示Linux系统中空闲的.已用的物理内存及swap内存,及 ...

  6. .NET内存分析工具-dotMemory

    .NET内存分析工具-dotMemory 1.介绍 官网链接 引言 程序内存占用较大?内存溢出?需要分析生产环境程序怎么办? dotMemory 使您可以分析各种 .NET 和 .NET Core应用 ...

  7. iOS开发——高级篇——内存分析,Instruments

    一.内存分析 1.静态内存分析(Analyze)不运行程序,直接对代码进行内存分析,查看代码是否有内存泄露优点:分析速度快,并且可以对所有的代码进行内存分析缺点:分析结果不一定准确(没有运行程序,根据 ...

  8. C语言内存分析

    C语言内存分析 一.进制 概念:进制是一种计数方式,是数值的表现形式 4种主要的进制: ①. 十进制:0~9 ②. 二进制:0和1 ③. 八进制:0~7 ④. 十六进制:0~9+a b c d e f ...

  9. AndroidStudio MAT LeakCanary 内存分析之 LeakCanary

    现在我们换一种更清晰方便的方式:LeakCanary https://github.com/square/leakcanary 首先将LeakCanary绑在我们的app上 build.gradle ...

随机推荐

  1. 解决magento后台无法登陆/登陆没有反应的方法

    安装过magento的几个版本,安装好后在登陆后台的时候都遇到了点问题,用户名和密码都输入正确,就是登陆不了后台,经过研究发现,登陆不了后台的主要是因为magento自身缓存设置的问题,最模板解决方法 ...

  2. C++多线程环境下的构造函数

    多线程的环境里,我们总不可避免要使用锁.于是一个常见的场景就是: class ObjectWithLock { private: std::mutex mtx_; SomeResType shared ...

  3. 【AT91SAM3S】SAM3S-EK Demo工程中,LCD驱动程序的加载(函数指针结构体)

    为了调试LCD,在英倍特的板子上烧Atmel的sam3s-ek_demo_1.4_source示例代码.LCD显示正常了,却找不到LCD的驱动究竟在哪. 花了好久,追踪到了这个执行过程. 进入main ...

  4. Web网站与Web应用程序区别

    创建时的目录结构不同. WEB应用程序一般处理程序有命名空间,而网站中的没有.(因为应用程序最后要编译成一个DLL文件,会产生命名冲突,而网站每个页面会编译成每一个的DLL,不会文件内产生全名冲突). ...

  5. JavaCV 学习(二):使用 JavaCV + FFmpeg 制作拉流播放器

    一.前言 在 Android 音视频开发学习思路 中,我们不断的学习和了解音视频相关的知识,随着知识点不断的学习,我们现在应该做的事情,就是将知识点不断的串联起来.这样才能得到更深层次的领悟.通过整理 ...

  6. HDU1501 Zipper(DFS) 2016-07-24 15:04 65人阅读 评论(0) 收藏

    Zipper Problem Description Given three strings, you are to determine whether the third string can be ...

  7. CHAPTER 24 History of Our Planet 第24章 我们行星的历史

    CHAPTER 24 History of Our Planet 第24章 我们行星的历史 Uncovering the bones of ancient beasts is only part of ...

  8. Rhythmk 一步一步学 JAVA (19) JAVA IO 文件常用操作

    package com.rhythmk.filedemo; import java.io.BufferedReader; import java.io.File; import java.io.Fil ...

  9. 【洛谷P1801】黑匣子

    黑匣子 题目链接 看到题解中“维护两个堆”,突然想到了这道题的解法 维护两个堆:大根堆h1, 小根堆h2 大根堆里的是最小的i个值,小根堆里是剩下的值 每Add一个值时 插入到小根堆中, 再比较小根堆 ...

  10. hihocoder 1465 循环串匹配问题(后缀自动机)

    后缀自动机感觉好万能 tries图和ac自动机能做的,后缀自动机很多也都可以做 这里的循环匹配则是后缀自动机能做的另一个神奇功能 循环匹配意思就是S是abba, T是abb 问'abb', 'bba' ...