關於記憶體分配和拆裝箱的一些疑惑 和 解答總結

2022-03-12 22:58:50 字數 4534 閱讀 4934

堆:

全部使用堆會造成極低的效率。

引用型別物件任何時候都在堆裡。

值型別也有可能分配在託管堆上:

引用型別物件整個都在堆中,所以其中的值型別欄位也在堆中

陣列元素值儲存的都是引用【不管值型別還是引用型別】

陣列元素是值型別:值儲存在棧中,

引用型別:值儲存在堆中

對於值型別(pointstruct1),會在棧上開闢一塊新的空間,將資料完全複製過去,因此pointstruct2和pointstruct1是互相獨立的,對其中乙個的修改不會影響到另乙個;

對於引用型別(pointclass1),也會在棧上開闢乙個新的空間,將棧上的資料(指向堆上例項的指標)複製到新的空間, 但是注意,此處複製的是指標,也就是說棧上的兩個變數pointclass1和pointclass2雖然是不同的空間,但是它們的儲存內容---指標(記憶體位址), 都是指向堆上的同一例項

值型別賦值給引用型別【裝箱】:會在堆上開闢一塊新空間,將值型別資料複製到堆中,引用型別變數存放指標(棧中)。

引用型別賦值給值型別【拆箱】:

歸根結底,這些賦值轉換,裝箱拆箱,還是繼承關係間物件的轉換,不存在繼承關係,轉換就不可能實現。

引數傳遞——實參賦值給形參

當程式中進行引數傳遞的時候,也是預設按值傳遞,值型別複製資料本身,形成獨立的資料塊,引用型別複製引用,指向同一例項。簡單一點就是傳遞時複製棧上的資料到新的棧上空間。

當你申明變數的時候就會為它在記憶體中分配記憶體空間8個位元組(64bits系統)【用來儲存堆記憶體位址】,引用型別必須初始化【c#8 之前如果使用未賦值的變數vs中就會編譯報錯,c#8 引入了可為空引用型別才可以不賦值,例如 string? name;】

引用被建立的同時必須被初始化(指標則可以在任何時候被初始化)。

本質上,c#中引用的底層是乙個指標。【c++中好像引用是指標常量,即引用一旦宣告就不能和其他物件繫結到一起】

答案:當前的gc實現對於乙個空類來說,需要至少12個位元組的物件例項。如果乙個類沒有定義任何例項字段,它將產生4個或8個位元組的開銷(用於分配到棧上來對他進行引用)。其餘部分(8個位元組)的將由同步塊索引和型別物件指標占用。

乙個物件在堆中有一塊區域儲存它內部的字段和成員以及兩個額外成員(型別物件指標【指向的是system.type的物件位址】、 同步塊索引 ,初始時被賦值為-1。)

所以對於乙個空引用型別來說,他所占用的空間大小就是`12`【12位元組】。

指標所佔記憶體和作業系統有關

char比較特殊【string是char組成】,占有位元組數與編碼格式、中英文均有關係

見問題4。

實際上很多應用中,堆的分配演算法往往是採取多種演算法復合而成的,對於glibc來說,小於64位元組的採用物件池的方法,對於大於512位元組的採用最佳適配演算法,對於64位元組和512位元組之間的採取最佳折中策略;對於大於128kb的申請,它會直接使用mmap向作業系統申請空間。

所有的結構都預設繼承了該類valuetype,對的,是乙個類,也就是說所有的結構都是有繼承的,繼承了valuetype,也是因為這樣,所以結構不能再繼承類了,只能繼承介面,因為c#是單繼承的。

首先什麼時候會裝箱

(1)呼叫乙個形參為object的方法,而傳入的實參為值型別時,需要裝箱。

可通過過載函式避免

(2)另乙個用法,非泛型容器,裡邊元素型別為object。

可通過使用泛型容器避免。

(3)呼叫基類方法,a.tostring()、gettype()。

a.tostring()編譯器發現a重寫了tostring方法,會直接呼叫tostring的指令。因為a是值型別,編譯器不會出現多型行為。因此,直接呼叫,不裝箱。(注:tostring是a的基類system.valuetype的方法) 。此處重寫基類方法避免

當你呼叫值型別變數的gettype()方法時總是伴隨著裝箱過程,因為它不能被過載(非虛方法不能override)。(補一句,所有的值型別都是繼承於system.valuetype的)。可通過呼叫typeof() 運算子避免裝箱。

將值型別轉化為介面型別時也會進行裝箱操作,這是因為介面型別必須包含對堆上的乙個物件的引用。

(4)自定義strut結構值型別,避免裝箱拆箱

所以c# 自定義結構:需要重寫某些基類方法避免。

然而在.net託管環境中,clr提供了更自由的方式來控制struct中layout:我們可以在定義struct時,在struct上運用structlayoutattribute特性來控制成員的記憶體布局。預設情況下,struct例項中的字段在棧上的布局(layout)順序與宣告中的順序相同

a.[structlayout(layoutkind.sequential)]

struct structdeft//

c#編譯器會自動在上面運用[structlayout(layoutkind.sequential)]

b.[structlayout(layoutkind.explicit)]

[structlayout(layoutkind.explicit)]

struct

badstruct

sizeof(badstruct)得到的結果是9byte,顯然得出的基數9顯示clr並沒對結構體進行任何記憶體對齊(align);本身要占有10byte的資料卻只佔了9byte,顯然有些資料被丟失了,這也正是我給struct取badstruct作為名字的原因。如果在struct上運用了[structlayout(layoutkind.explicit)],計算fieldoffset一定要小心

c.[structlayout(layoutkind.auto)]

sizeof(structauto)得到的結果是12byte。下面來測試下這structauto的三個欄位是如何擺放的:

unsafe

", (int)&(s.i)));

console.writeline(

string.format("

c:", (int)&(s.c)));

console.writeline(

string.format("

b:", (int)&(s.b)));}//

測試結果:

i:1242180

c:1242172

b:1242181

即clr會對結構體中的字段順序進行調整,將i調到c之後,使得structauto的例項s占有盡可能少的記憶體,並進行4byte的記憶體對齊(align),

結論:

預設(layoutkind.sequential)情況下,clr對struct的layout的處理方法與c/c++中預設的處理方式相同,即按照結構中占用空間最大的成員進行對齊(align);

使用layoutkind.explicit的情況下,clr不對結構體進行任何記憶體對齊(align),而且我們要小心就是fieldoffset;

使用layoutkind.auto的情況下,clr會對結構體中的字段順序進行調整,使例項占有盡可能少的記憶體,並進行4byte的記憶體對齊(align)。

所有資料都是值型別【基本型別+結構型別 如datetime】例項儲存的資料。但在記憶體中位置不一樣,

純基本型別物件儲存在棧中,記憶體分配效率高

不純的基本型別【引用類例項中值型別成員,陣列值型別元素(元素都是引用,元素值在堆或棧中)】,記憶體分配效率低

資料最終都是由純基本型別組成的【或字串這個特殊的引用型別,編碼不同占用位元組數不同】,純基本型別又是由乙個乙個位元組組成的【int佔32位4個位元組,byte8位佔乙個位元組,short16位2個位元組,long64位8位元組。】。都是可以預知記憶體大小的。

計算機中有個儲存資料的叫儲存器(分為 ram 和 rom), 首先是儲存在 記憶體中(也就是ram 隨機儲存器,與cpu 直接互動的,其內部有好多的元器件進行儲存,這個元器件就有兩種狀態0或1也就是有電,沒電(多好要麼有要麼沒),雖然乙個元器件只有兩種狀態,但是多個組合就很大了,突然一組合就有了 bit,byte,kb,mb,gb,tb,pb,eb 的概念了 那麼元器件也就有了另乙個名字 位元(bit)或位,),在記憶體中資料有不同的型別,而不同型別資料占用的位元組數不一樣【相同型別的不同資料根據編碼規則分別由 一些位元組(單位元組或多位元組)唯一表示】,如 int 佔4個位元組,byte 佔1 個位元組,字元根據編碼不同占用位元組數也不同,乙個漢字unicode編碼為兩個位元組,utf8編碼為三個位元組,為了正確訪問這些儲存的資料,必須給每個位元組都編上號碼,每個編號都是惟一的,根據編號就能準確找到某個位元組,而在記憶體中位元組的編號又被稱為位址(address)或指標(pointer)。

關於z index的一些疑惑

當我使用z index這個屬性的時候,為了實現首頁的banner圖,我還同是用到了乙個bootstrap的carousels外掛程式,然後我就鬱悶了,開始沒有發現,然後出現了在360瀏覽器上當banner滑動的時候我的頭部居然閃爍的現象,開始一直找不到原因。最後仔細的觀察居然是這個屬性的問題就是z ...

關於SOA 和 BPM 的一些疑惑!

不得不說,作為乙個coder,需要不斷地更新一下自己的概念,不過感覺即便只是j2ee,概念都是鋪天蓋地的,作為剛畢業投入工作不久的新人來說,路還是很長啊!首先,宣告,不是介紹什麼,只是想請教些問題,雖然有點長,但希望解決一些迷惑!第一次發貼啊!因為畢業前一直做j2ee方面的開發,也有個幾個專案經驗,...

關於Marching Cube的一些疑惑思考

最近學習mc表面繪製,對於開始對於cg方面的一些知識不是很明白,搞的一頭霧水,於是就零零碎碎參考一些網上的程式來學習。主要參考的有3d med 的手冊,網上的一些程式,如 以及跟蹤vtk源 還有這個 但是在閱讀的時候產生的兩個疑惑,表示怎麼算出來的,看了書上的不是很明白,另乙個問題是得到的三角麵片怎...