網站首頁 編程語言 正文
基本
哪些屬于引用類型
類(object,string),接口、數組、委托
引用類型分配在哪里
- 引用類型變量位于線程棧。
- 引用類型實例分配在托管堆上。
- 當引用類型實例的大小小于85000bytes,被分配在GC堆上,當大于或等于85000bytes,被分配在LOH(Large Object Heap)上。
變量(Variable),對象(Object),實例(Instance)
變量:
變量分配在線程棧上。
變量可以是值類型,也可以是引用類型。
當變量是引用類型時,包含了對對象的引用(內存地址),也叫做"對象引用"。
對象:
對類、接口、委托和數組等的一個抽象描述。
實例:
在堆上創建的對象,稱為對象實例。
引用類型沒有new意味著什么?
Object a = null;
Console.WriteLine(a.ToString());
運行報錯"未將對象引用設置到對象實例"。
意思是,在線程棧上創建的變量a沒有指向到堆上的對象實例。
托管堆上的垃圾回收
GC會遍歷所有托管堆上的對象,按照一定的遞歸遍歷算法,對那些沒有被引用的不可訪問對象實施回收。
new的背后發生了什么
class Program
{
static void Main(string[] args)
{
Person p;
p = new Person(20);
}
}
public class Person
{
public int _age;
public Person(int age)
{
_age = age;
}
public Person()
{
}
}
另外,引用類型的值,比如這里的引用類型Person中的值_age也被分配在托管堆上。???
線程棧上的2個變量引用同一個對象實例的內存地址
線程棧上的2個變量引用同一個對象實例的內存地址,改變其中一個變量的值會影響到另外一個變量。
class Program
{
static void Main(string[] args)
{
Person p1 = new Person(20);
Person p2 = p1;
Console.WriteLine("沒有改變時p2的年齡是:" + p2._age + "歲");
p1._age = 18;
Console.WriteLine("改變p1的值,p2的年齡也被改變了,現在是:" + p2._age + "歲,真好,年輕了!");
Console.ReadKey();
}
}
public class Person
{
public int _age;
public Person(int age)
{
_age = age;
}
public Person()
{
}
}
string類型是特殊的引用類型
特殊性體現在
從應用角度體現了值類型語義,從內存角度實現為引用類型存儲,位于托管堆。
什么是string
可以看作是char的集合char[]????
string創建與實例化
string str = "Hello";
以下錯誤
String str = new String("Hello");
因為System.String沒有提供此構造函數
以下可以
Char[] cs = {'a', 'b','c'};
String strArr = new String(cs);
但很少使用這種方式。
字符串的恒定性Immutability
是指字符串一經創建,就不可改變。
字符串一旦創建,在托管堆上分配一塊連續的內存空間。
恒定性的好處:
對String對象的任意操作,不會改變原字符串。
操作字符串不會出現線程同步的問題。
成就了字符串駐留。
恒定性的不足:
因為恒定性,對字符串的任何操作,比如字符串比較,字符串鏈接,字符串格式化等都會創建新的字符串,這樣造成內存與性能的雙重損耗。如下:
public static void Main()
{
string str = "This is a test about immuntablility of string type.";
Console.WriteLine(str.Inseert(0,"Hi").Substring(19).ToUpper());
Console.WriteLine(str);
}
由于Insert,Substring,ToUpper這些方法,都會創建出新的臨時字符串,而這些新的字符串不被其他代碼引用的時候,就會被垃圾回收,造成性能上的損失。
恒定性的前提,String為密封類:
public sealed class String:IComparable, ICloneable,IConvertible,IComparable<string>,IEnumerable<char>,IEnumerable,IEquatable<string>
字符串駐留String Interning
MSDN對于字符駐留的定義:公共語言運行庫通過維護一個哈希表(Hash Table)來存放字符串,該表成為拘留池,也叫駐留池。
字符串駐留彌補了恒定性的不足:
對于相同的字符串,CLR不會不會為其分配內存空間,而是共享同一內存。
CLR內部維護了一個哈希表HashTable來管理其創建的大部分String對象。key是string本身,value是string對應的內存地址。
駐留的2個靜態方法:
public static string Intern(string str);
當str位于作為key位于CLR的駐留池時,返回對str的引用,否則將str字符串添加到hash table中,作為key,并返回引用。
public static string IsInterned(string str);
當str位于作為key位于CLR的駐留池時,返回對str的引用,否則返回null引用,也不添加到hash table中。
字符串駐留是進程級的
可以跨應用程序域AppDomain而存在,駐留池在CLR加載時創建,分配在System Domain中,被進程所有AppDomain所共享,其生命周期不受GC控制。
例子1:
static void Main(string[] args)
{
string strA = "ab";
string strB = "ab";
Console.WriteLine(ReferenceEquals(strA,strB));
string strC = "a";
string strD = strC + "b";
Console.WriteLine(ReferenceEquals(strA, strD));
strD = String.Intern(strD);
Console.WriteLine(ReferenceEquals(strA,strD));
Console.ReadKey();
}
返回:
true
false
true
分析:
- strA與strB內容相同,在hash table中的key相同,對應了一樣的引用地址,所以返回true。
- strD的內容雖然與strA相同,但由于是動態生成的,不會把hash table中key為ab的引用地址賦值給strD,所以strA與strD引用地址不一樣,返回false。
- strD = String.Intern(strD);手動對strD實施駐留,并發現hash table中已經有了ab這個key,就把對應的引用地址賦值給了strD,這樣,strA與strD引用地址相同,返回true。
例子2:
static void Main(string[] args)
{
string s1 = "abc";
string s2 = "ab";
string s3 = s2 + "c";
Console.WriteLine(string.IsInterned(s3) ?? "null");
Console.WriteLine(ReferenceEquals(s1,s3));
Console.ReadKey();
}
返回:
abc
false???
分析:
- string.IsInterned(s3)對s3進行手動駐留,發現hash table中abc這個key,于是,就返回abc的引用地址。但并沒有把引用地址賦值給s3。
- s1和s3的引用地址還是不一樣,返回false。
例子3:
static void Main(string[] args)
{
string strA = "abcdef";
string strC = "abc";
string strD = strC + "def";
Console.WriteLine(ReferenceEquals(strA,strD));
string StrE = "abc" + "def";
Console.WriteLine(ReferenceEquals(strA,StrE));
Console.ReadKey();
}
返回:
False,???????
true
分析:
- 因為strD = strC + "def"中strD的內容雖然與strA想同,但因為是動態生成的,不會被添加到hash table中,所以引用地址不一樣,返回false。
- "abc"+"def在IL中呈現為abcdef,不是動態生成的,并且發現hash table中已經有了abcdef這個key,于是就把對應的引用地址賦值給了strE,這樣strA和StrE就有了相同的引用地址,返回true。如圖:
例子4:
static void Main(string[] args)
{
string s = "abc";
//IsInterned()獲取字符串變量的引用
Console.WriteLine(string.IsInterned(s) ?? "null");
Console.ReadKey();
}
返回
"abc"。
分析:通過string s = "abc"使得hash table中有abc這個key,當進行string.IsInterned(s)手動駐留判斷的時候,發現有abc這個key,就把對應的引用地址返回。
例子5:
class Program
{
static void Main(string[] args)
{
string s = "ab";
s += "c";
//IsInterned()獲取字符串變量的引用
Console.WriteLine(string.IsInterned(s) ?? "null");
Console.ReadKey();
}
}
返回
null
分析:通過string s = "ab";使得hash table中有了ab這個key,s += "c"是動態拼接,不會把abc放到hashtable中,所以當通過string.IsInterned(s)手動駐留判斷的時候,發現沒有abc這個key,就返回null。
原文鏈接:https://www.cnblogs.com/darrenji/p/3599550.html
相關推薦
- 2022-12-07 C++中new的用法及說明_C 語言
- 2022-11-19 Golang?cron?定時器和定時任務的使用場景_Golang
- 2023-01-30 uniapp語音識別(訊飛語音)轉文字_其它相關
- 2023-01-26 如何在.Net?7中將Query綁定到數組詳解_實用技巧
- 2023-03-18 C#?DataTable.Select()根據條件篩選數據問題_C#教程
- 2022-10-27 QT線程QThread的使用介紹_C 語言
- 2021-10-04 Flutter輸入框TextField屬性及監聽事件介紹_Android
- 2022-06-20 基于C#實現語音識別功能詳解_C#教程
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支