原文如下:类与结构有很多相似之处:结构可以实现接口,并且可以具有与类相同的成员类型。然而,结构在几个重要方面不同于类:结构为值类型而不是引用类型,并且结构不支持继承。结构的值存储在“在堆栈上”或“内联”。细心的程序员有时可以通过聪明地使用结构来增强性能。例如,将 Point 定义为结构而不是类在运行时可以节省很多内存空间。下面的程序创建并初始化一个 100 点的数组。对于作为类实现的 Point,出现了 101 个实例对象,因为数组需要一个,它的 100 个元素每个都需要一个。class Point
{
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
class Test
{
static void Main() {
Point[] points = new Point[100];
for (int i = 0; i < 100; i++)
points[i] = new Point(i, i*i);
}
}
如果将 Point 改为作为结构实现,如struct Point
{
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
则只出现一个实例对象(用于数组的对象)。Point 实例在数组中内联分配。此优化可能会被误用。使用结构而不是类还会使应用程序运行得更慢或占用更多的内存,因为将结构实例作为值参数传递会导致创建结构的副本。
为什么会创建101个呢?什么是内联分配呢
{
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
class Test
{
static void Main() {
Point[] points = new Point[100];
for (int i = 0; i < 100; i++)
points[i] = new Point(i, i*i);
}
}
如果将 Point 改为作为结构实现,如struct Point
{
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
则只出现一个实例对象(用于数组的对象)。Point 实例在数组中内联分配。此优化可能会被误用。使用结构而不是类还会使应用程序运行得更慢或占用更多的内存,因为将结构实例作为值参数传递会导致创建结构的副本。
为什么会创建101个呢?什么是内联分配呢
解决方案 »
- (有图)在封装字段的时候,update reference里有个external和all这两个选项,请问有什么区别?
- C# 中文编码
- 加密密钥如何确定?
- 请问如何删除磁盘下某种格式的文件?
- 端口的若干问题?——操,标题多长才算够长!
- 关于附加MSComm控件安装包的制作
- 菜鸟说话了 C#
- 判断datagridview中某个单元格是否得到了焦点
- 大家在项目中作menu或toolbar时是如何设计的?
- 遇到一个打印数组的例子,有些不明白。
- 自定义DataGridComboBoxColumn在新行中编辑,如何实现DataGridTestBoxColumn 那样,当更改数据以后,便增加新行,附代码
- 用户窗体控件的自定义事件问题
如果是struct,则GC堆上只有一个Point[]对象,里面直接记录对象的内容并且紧密相连,这个和C/C++内的array行为相同实际上在上面例子的情况,应该使用class的性能更高,因为如果用struct的话,需要做100次装箱的操作,而这个过程等于线程堆栈和GC堆上的数据拷贝,很损伤性能
而如果出现了Point p = points[i]这样的代码,则还要进行100次拆箱的操作
这里所说的内联分配我估计它的意思就是指在栈上分配空间。
public int x, y; public CPoint(int x, int y) {
this.x = x;
this.y = y;
}
}internal struct SPoint {
public int x, y; public SPoint(int x, int y) {
this.x = x;
this.y = y;
}
}class Test {
private const int TestCount = 1000000; private static void Main() {
// Test Class
long startTime = DateTime.Now.Ticks; CPoint[] cPoints = new CPoint[TestCount];
for (int i = 0; i < TestCount; i++) {
cPoints[i] = new CPoint(i, i*i);
} Console.WriteLine(DateTime.Now.Ticks - startTime); // Test Struct
startTime = DateTime.Now.Ticks; SPoint[] sPoints = new SPoint[TestCount];
for (int i = 0; i < TestCount; i++) {
sPoints[i] = new SPoint(i, i*i);
} Console.WriteLine(DateTime.Now.Ticks - startTime); Console.ReadLine();
}
}
你错了,.NET内所有的数组都在堆上// 这段代码中的new(Test Struct中的)只是调用struct的构造函数而已
points[i] = new Point(i, i*i)这样的代码没有装箱操作,但很多情况是,自己写的struct往往都没有构造函数(除了默认的),这样得先在线程上建立值类型对象,做了一些操作之后,再装箱到数组内,这样就会出现我前面讲的问题;而如果先new xxx到数组内,再给各个字段辅值,代价会更高,因为每次辅值都由隐藏的拆箱的过程
所以你的测试代码并没有完全说明问题而Point p = points[i]这样的代码或者points[i].xxx这样的代码,拆箱的代价会很高
是不是每个应用程序域都有的哪个内置池呀,可能是实例对象;;;;
string a;是一个对像
string a="ttt";也是一个,
加一起不就是101个嘛,
结构在栈上,只分配一次内存空间,
要为类的实例在内存中分配空间,还要为引用这个实例的变量分配。
可能是这样啊,,上边的都跑题了。和拆箱有什么关系呀
你错了,.NET内所有的数组都在堆上
A:Point[]怎么可能是分配在椎上的呢?请看下面这段代码。
Point[] pts;
pts = new Point[10];
十个Point在椎上面,而那个pts就在栈上面,你可以用ildasm看一看
.maxstack 2
.locals init ([0] valuetype SPoint[] sPoints,
[1] int32 i)
i是后面的循环变量。
public int x, y; public SPoint(int x, int y) {
this.x = x;
this.y = y;
}
}class Test {
private const int TestCount = 10; private static void Main() {
SPoint[] sPoints = new SPoint[TestCount]; for (int i = 0; i < TestCount; i++) {
// sPoints[i] = new SPoint(i,i);
sPoints[i] = new SPoint();
sPoints[i].x = i;
sPoints[i].y = i;
} SPoint p = sPoints[7];
p.x=99;
Console.WriteLine(sPoints[7].x);//显示7 Console.ReadLine();
}
}
再看看这段代码,SPoint p = sPoints[7];并不是什么UnBoxing操作,你可以用ILDasm看的,里面没有unbox指令的,而是将第八个元素复制给了p,这里是复制而不是引用,因为继承于ValueType的值类型都是实现深Copy的。
如果在栈上分配,那么:
1、System.Array是值类型,应该继承System.ValueType
2、将不能创建占用内存超过最大栈空间的数组(比如new byte[1024*1024*10],内存占用达到10MB),据我试验,.NET程序栈空间在1MB左右
3、把一个Array从一个函数传递到另一个函数,CLR将把Array复制一遍,所以后者对Array的修改不会影响前者
你可以对这些结论测试.NET Framework程序设计一书也明确指出.NET的数组只能分配在堆上// 里面没有unbox指令的,而是将第八个元素复制给了p
如果你坚持要把堆和堆栈上复制数据的过程和unbox过程分开,那你是对的
如果你把值类型赋给一个object,才会使用box指令;再转换回来的时候,才会使用unbox指令
数组在这里有点特殊,虽然没有用这两个指令,但是线程堆栈和堆上的数据复制确实发生了确实有点跑题 :-) 不过这些都是相关的问题
就是《.NET Framework程序设计》一书中P310页中左边的那个myIntegers。
To 楼主:上面这本书P310页这个图就会告诉你什么答案,包括你问的内联。
但“数组在这里有点特殊,虽然没有用这两个指令,但是线程堆栈和堆上的数据复制确实发生了”这句话你是如何得到的结论?希望能说明一下。