.NET下的記憶體分配機制
對於任何物件的產生,都伴隨著記憶體空間的分配,那麼本文將初步介紹一下.NET下,是如何進行記憶體分配的。
1.概述
CLR支援兩種基本型別:值型別和引用型別。因此,還是把MSDN這張經典檢視拿出來做個鋪墊。
關於具體每種分類都有哪些型別,這裡不做介紹。
2.記憶體分配原則
在.NET Framework中,記憶體中的資源(即所有二進位制資訊的集合)分為"託管資源"和"非託管資源".託管資源必須接受.NET Framework的CLR(通用語言執行時)的管理(諸如記憶體型別安全性檢查),而非託管資源則不必接受.NET Framework的CLR管理. (瞭解更多區別請參閱.NET Framework或C#的高階程式設計資料)
託管資源在.NET Framework中又分別存放在兩種地方: "堆疊"和"託管堆"(以下簡稱"堆")。本文只討論託管資源的記憶體分配。
那麼.NET的託管資源記憶體分配機制如何呢?
實際上,資料在記憶體中的分配位置,取決於該變數的資料型別。
對於記憶體分配的更詳細位置,可以描述如下:
• 對於值型別的例項,CLR在執行時有兩種分配方式:(1) 如果該值型別的例項作為型別中的方法(Method)中的區域性變數,則該例項被建立線上程棧上;(2) 如果該值型別的例項作為型別的成員,則該例項作為引用型別(引用型別在GC堆或者LOH上建立)的例項的一部分,被建立在GC堆上。下面這段程式碼演示了這兩種情況:
- publicclass Test1
- {
-
privateint i;
- //上面(2)中的情況,生成Test的例項的同時,int型別的例項i被建立在GC堆上
- public Test1()
- {
- byte b =0;
- //(1)中的情況,byte型別的例項b被建立在執行這段程式碼的執行緒棧上
- }
- }
• 對於引用型別的例項,CLR在執行時也有兩種分配方式:(1) 如果該引用型別的例項的Size<85000Byte,則該例項被建立在GC(Garbage Collection)堆上(當CLR在分配和回收物件時,GC可能會對GC堆進行壓縮);(2) 如果該引用型別的例項的Size>=85000byte,則該例項被建立在LOH(Large
Object Heap)上
- publicclass Test2
- {
- privateint[] intArr;
- public Test2()
- {
- private Object o = new Object();
- //引用o存線上程棧上,它指向GC堆上的Object例項
- intArr = newint[21250];
- //符合(2)中的Size條件,int陣列的例項被建立在LOH上
- }
- }
這裡要注意的是,對於引用物件,他包括了引用和物件例項兩部分,例項需要通過對其儲存位置的引用來訪問,對於private Object o = new Object(),其實可以分解為兩句話:
private Object o;
o = new Object();
其中private Object o是定義了物件的引用,也就是記錄物件例項的指標,而不是物件本身。這個引用儲存於堆疊中,佔用4個位元組;當沒有使用o = new Object()時,引用本身的值為null,也就是不指向任何有效位置;
當o = new Object()後,才真正根據物件的大小,在託管堆中分配空間給物件例項,然後將例項的指標位置賦值給前面的引用。這才完成一個物件的例項化。
在例如,現在有MyStruct和MyClass分別代表一個結構體和一個類,如下:
- using System;
- publicclass Test
- {
- staticvoid Main()
- {
- //定義值型別和引用型別,並完成初始化
- MyStruct myStruct = new MyStruct();
- MyClass myClass = new MyClass();
- //定義另一個值型別和引用型別,
- //以便了解其記憶體區別
- MyStruct myStruct2 = new MyStruct();
- myStruct2 = myStruct;
- MyClass myClass2 = new MyClass();
- myClass2 = myClass;
- }
- }
在上述的過程中,我們分別定義了值型別變數myStruct和引用型別變數myClass,並使用new操作符完成記憶體分配和初始化操作。而我們在此強調的是myStruct和myClass兩個變數在記憶體分配方面的區別,還是以一個簡明的圖來展示一下:
我們知道,每個變數或者程式都有其堆疊,不同的變數不能共有同一個堆疊地址,因此myStruct和myStruct2在堆疊中一定佔用了不同的堆疊地址,儘管經過了變數的傳遞,實際的記憶體還是分配在不同的地址上,如果我們再對myStruct2變數改變時,顯然不會影響到myStruct的資料。從圖中我們還可以顯而易見的看出,myStruct在堆疊中包含其例項資料,而myClass在堆疊中只是儲存了其例項資料的引用地址,實際的資料儲存在託管堆中。因此,就有可能不同的變數儲存了同一地址的資料引用,當資料從一個引用型別變數傳遞到另一個相同型別的引用型別變數時,傳遞的是其引用地址而不是實際的資料,因此一個變數的改變會影響另一個變數的值。從上面的分析就可以明白的知道這樣一個簡單的道理:值型別和引用型別在記憶體中的分配區別是決定其應用不同的根本原因,由此我們就可以很容易的解釋為什麼引數傳遞時,按值傳遞不會改變形參值,而按址傳遞會改變行參的值,道理正在於此。
3. 巢狀結構
上面講解了型別在記憶體中分配的基本原則,那麼這裡繼續介紹各種型別相互巢狀時候,這些型別是如何分配的。其實還是完全依據上面的基本分配規則的。
所謂的巢狀結構就是在值型別中巢狀定義了引用型別,或者在引用型別變數中巢狀定義了值型別。
• 引用型別巢狀值型別
值型別如果巢狀在引用型別時,也就是值型別在內聯的結構中時,其記憶體分配是什麼樣子呢? 其實很簡單,例如類的私有欄位如果為值型別,那它作為引用型別例項的一部分,也分配在託管堆上。例如:
-
相關推薦
.NET下的記憶體分配機制
對於任何物件的產生,都伴隨著記憶體空間的分配,那麼本文將初步介紹一下.NET下,是如何進行記憶體分配的。 1.概述 CLR支援兩種基本型別:值型別和引用型別。因此,還是把MSDN這張經典檢視拿出來做個鋪墊。 關於具體每種分類都有哪些型別,
記憶體探尋1之——值型別和引用型別的記憶體分配機制
String物件和值型別的記憶體分配機制: 同樣由前延伸,上上篇《由String型別分析,所產生的對引數傳遞之惑的解答》中,最後提及,如果將引用型別的按值傳遞和按引用傳遞,用託管堆表
malloc動態記憶體分配機制原理_及_linux/proc/介紹
程序系統資源的使用原理 大部分程序通過glibc申請使用記憶體,但是glibc也是一個應用程式庫,它最終也是要呼叫作業系統的記憶體管理介面來使用記憶體。大部分情況下,glibc對使用者和作業系統是透
通過簡單的程式碼分析.NET物件記憶體分配
System.Windows.Forms.Button btn = new Button(); 以中間賦值符號為界限,先看左邊。System.Windows.Forms 是名稱空間,放在一邊。後面是 Button btn,也就是型別名稱,變數名的形式。 其實這跟 int i 沒區別,因為 int i 就是
python記憶體分配機制
python中數值型別是不可變物件,當程式試圖改變資料的值時,程式會重新生成新的資料,而不是改變原來的資料。 python函式的引數都是物件的引用,如果在引用不可變物件時嘗試修改物件,程式會在函式中生
Java記憶體分配機制
Java存放物件、變數等資訊需要分配記憶體進行儲存,分配及儲存區原理如下: 1.暫存器 它是唯一位域處理器內部的儲存區。所以它是最快的,數量也是極其有限的,並且和 C,C++不一樣的是,Java暫存器是根據程式需求進行分配的,你不能控制、也不能向它“建議“分配方式。在 java 中暫存器對於程式設計
淺談windows和linux下記憶體分配規律
首先先說明下,本文中程式碼來自牛刀教程。寫的很不錯。給我不少的啟發。謝謝了 我們都知道,在使用C語言時,比如定義一個數組,一個變數。那麼系統都會隨機的分配記憶體。那麼你知道記憶體分配的規律嗎? 讓我們用兩個實驗來說明windows和linux下,記憶體分配方式的不同。 同一
Java虛擬機器記憶體分配機制與啟動引數說明
-Xms :表示java虛擬機器堆區記憶體初始記憶體分配的大小,通常為作業系統可用記憶體的1/64大小即可,但仍需按照實際情況進行分配。-Xmx: 表示java虛擬機器堆區記憶體可被分配的最大上限,通常為作業系統可用記憶體的1/4大小。但是開發過程中,通常會將 -Xms 與 -Xmx兩個引數的配置相同的值,其
淺談記憶體對齊--linux和windows平臺下記憶體分配的差異
一.記憶體對齊的初步講解 記憶體對齊可以用一句話來概括: “資料項只能儲存在地址是資料項大小的整數倍的記憶體位置上” 例如int型別佔用4個位元組,地址只能在0,4,8等位置上。 例1: #include <stdio.h> struct xx{
STL中vector的記憶體分配機制
一些好的公司校園招聘過程中(包括筆試、面試環節),經常會涉及到STL中vector的使用(主要是筆試)及其效能(面試)的分析。今天看了下相關文章,也寫了幾個小的測試程式跑了跑。算是總結下,希望對需要的人有幫助。 關於vector,簡單地講就是一個動態陣列,裡面有一個指標
Java的記憶體分配機制(初步整理)
Java程式是執行在Java虛擬機器(Java Virtual Machine,JVM)上的,可以把JVM理解為Java程式和作業系統之間的橋樑,JVM實現了Java的跨平臺,Java記憶體分配原理一切都是在JVM中進行的,JVM是記憶體分配原理的基礎與前提。
memcached的一些研究(關於memcached的記憶體分配機制)
memcached作為快取已被應用的非常多,memcached的資料結構非常簡單,就是key-value的儲存,瞭解下memcached的記憶體分配機制有助於更好的使用memcache memcached相關的記憶體術語 chunk:資料是儲存
記憶體對齊的初步講解--linux和windows平臺下記憶體分配的差異
一.記憶體對齊的初步講解 記憶體對齊可以用一句話來概括: “資料項只能儲存在地址是資料項大小的整數倍的記憶體位置上” 例如int型別佔用4個位元組,地址只能在0,4,8等位置上。 例1: #include <stdio.h> struct xx{
Java記憶體分配機制詳解
文章轉載自:http://www.cnblogs.com/zhguang/p/3257367.html 本文僅載抄了部分內容,若想知道JVM記憶體全量資訊,請檢視原文 Java記憶體分配機制 這裡所說的記憶體分配,主要指的是在堆上的分配,一般的,物件的記憶體分配都是在堆
JVM的藝術-物件建立與記憶體分配機制深度剖析
# JVM的藝術-物件建立與記憶體分配機制深度剖析 > ##### 引言 本章將介紹jvm的物件建立與記憶體分配。徹底帶你瞭解jvm的建立過程以及記憶體分配的原理和區域,以及包含的內容。 > ### 物件的建立 ![](https://img2020.cnblogs.com/ot
JVM的垃圾收集機制和記憶體分配策略
首先給大家看一下JVM的資料區模型。 上圖是JVM的資料區模型。但是在Hotspot JVM中,我們知道執行時常量是屬於方法區的,而方法區又屬於堆。對於棧,在hotspot中虛擬機器棧和本地棧是合二為一的。 這裡在順便說一說虛擬機器物件的結構,如下圖所示
三、Java虛擬機器自動記憶體管理機制、物件建立及記憶體分配
1、物件是如何建立: 步驟: (1)、虛擬機器遇到new <類名>的指令---->根據new的引數是否在常量池中定位一個類的符號引用 (2)、檢測該符號引用代表的類是否已經被載入、解析、和初始化。(如果沒有則
經典String str = new String("abc")記憶體分配問題,研究下字串到底該怎麼樣初始化,順便很好的解釋下Java的intern()(在文章結尾)
大佬這個部落格很厲害,解決了我一直以來的困惑; Java中以下兩句有什麼區別呢?String str1="abc"; String str2=new String("abc"); Java把記憶體劃分成兩種:一種是棧記憶體,一種是堆記憶體。 在函式中定義的一些基本型別
自動記憶體管理機制(4)- 記憶體分配和回收策略
自動記憶體管理機制(4)- 記憶體分配和回收策略 Java所承諾的自動記憶體管理主要是針對物件記憶體的回收和物件記憶體的分配。 在Java虛擬機器的五塊記憶體空間中,程式計數器、Java虛擬機器棧、本地方法棧記憶體的分配和回收都具有確定性,一般在編譯階段就能確定需要分配的記憶體大小,
Java虛擬機器筆記-1(Java技術體系&自動記憶體管理機制&記憶體區域與記憶體溢位&垃圾收集器與記憶體分配策略)
世界上沒有完美的程式,但寫程式是不斷追求完美的過程。 Devices(裝置、裝置)、GlassFish(商業相容應用伺服器) 目錄 1. Java技術體系包括: Java技術體系的4個平臺 虛擬機器分類 HotSpot VM 模組化、混合程式設計 多核並行