C#-值类型、引用类型
一:值类型、引用类型
1.1 值类型
整型、浮点、bool、char、枚举、结构体
仅需一段内存来存储实际的数据、单独定义时放在栈上
1.2 引用类型
string、数组、类(自定义类、内置的类)
需2段内存
-
存放实际数据、位于堆中(因为占得位置比较大)
-
存放引用,指向数据在堆中的位置(保存地址)
二:值类型和引用类型的区别
2.1 使用上的区别
值类型:在相互赋值时,把内容拷贝给了对方,它变我不变
引用类型:在相互赋值时,让两者指向同一个值,它变我也变
2.2 为什么有以上区别
两者所存储的内存区域及存储方式不同
值: 栈 → 系统分配,自动回收,小而快
引用:堆 → 手动申请和释放,大而慢
在使用引用类型赋值时,赋值的是引用类型的引用,即地址
值类型数组,数组中直接存储值
引用类型数组,数组中存储的是引用(内存地址)
new 了 就是在堆中开了新空间,和之前的,没有什么关系了
三:string是特殊引用类型
string是引用类型,但它具备,值类型的特征→它变我不变
string缺点:频繁改变string,会重新赋值,会产生 内存垃圾。
string型数据在赋值时,原数据不变。因为string在赋值时会在堆中重新分配内存空间,并修改栈中存储的地址
3.1 string使用上的缺点
-
修改会导致频繁的内存分配和垃圾收集
-
内存分配:每次使用
+
运算符或Concat
方法连接字符串时,都会分配内存以创建一个新的字符串对象。在循环中进行字符串连接会导致性能问题。 -
性能开销:对于需要频繁修改字符串内容的场景,使用
string
可能导致不必要的性能开销。例如,在构建一个由多个部分组成的字符串时,每部分的添加都涉及创建一个新对象。 -
不支持缓冲区操作:
string
类型不支持直接操作字符缓冲区,这在需要处理大量文本数据时可能不够高效。 -
隐式装箱:由于
string
是引用类型,当它被赋值给一个object
类型变量时,会发生装箱操作,这可能会增加额外的性能开销。 -
安全性:不可变的
string
对象可以提高安全性,因为它们不能被意外修改。然而,在某些情况下,这可能限制了对字符串的直接操作。 -
国际化和格式化:在处理国际化应用程序时,
string
类型可能不足以处理复杂的文本格式化和文化差异。 -
编码问题:在处理非ASCII字符时,
string
类型默认使用 UTF-16 编码,这在处理大量非ASCII文本时可能导致内存使用增加。
3.2 string的优化替代方案
-
StringBuilder
类:频繁的字符串修改或连接操作 -
处理大量数据,考虑使用
Span<T>
或ReadOnlySpan<T>
来避免不必要的内存分配。 -
使用
string.IsNullOrEmpty
或string.IsNullOrWhiteSpace
: 在检查空字符串时,使用string.IsNullOrEmpty
或string.IsNullOrWhiteSpace
而不是== null
或== ""
可以避免不必要的字符串创建。