/** Added to satisfy initialization of entry elements --* this is where the extra time is spent resizing the Entry array* **/for (int i = 0 ; i < prime ; i++){destinationArray[i] = new Entry( );}/* *********************************************** */
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);}}
另一种方法是使Point成为结构。
struct Point{public int x, y;
public Point(int x, int y) {this.x = x;this.y = y;}}
public struct MyPoint{public int X; // Value Typepublic int Y; // Value Type}
public class MyPointWithName{public int X; // Value Typepublic int Y; // Value Typepublic string Name; // Reference Type}
public struct IntStruct {public int Value {get; set;}}
执行以下结果会导致存储在内存中的结构的5个实例:
var struct1 = new IntStruct() { Value = 0 }; // originalvar struct2 = struct1; // A copy is madevar struct3 = struct2; // A copy is madevar struct4 = struct3; // A copy is madevar struct5 = struct4; // A copy is made
// NOTE: A "copy" will occur when you pass a struct into a method parameter.// To avoid the "copy", use the ref keyword.
// Although structs are designed to use less system resources// than classes. If used incorrectly, they could use significantly more.
类是引用类型。当您将类分配给新变量时,该变量包含对原始类对象的引用。
public class IntClass {public int Value {get; set;}}
执行以下命令会导致内存中类对象的只有一个实例。
var class1 = new IntClass() { Value = 0 };var class2 = class1; // A reference is made to class1var class3 = class2; // A reference is made to class1var class4 = class3; // A reference is made to class1var class5 = class4; // A reference is made to class1
var struct1 = new IntStruct() { Value = 0 };var struct2 = struct1;struct2.Value = 1;// At this point, a developer may be surprised when// struct1.Value is 0 and not 1
BenchmarkDotNet=v0.10.8, OS=Windows 10 Redstone 2 (10.0.15063)Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4Frequency=3233542 Hz, Resolution=309.2584 ns, Timer=TSC[Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.7.2101.1Clr : Clr 4.0.30319.42000, 64bit RyuJIT-v4.7.2101.1Core : .NET Core 4.6.25211.01, 64bit RyuJIT
Method | Job | Runtime | Mean | Error | StdDev | Min | Max | Median | Rank | Gen 0 | Allocated |---------------- |----- |-------- |----------:|----------:|----------:|----------:|----------:|----------:|-----:|-------:|----------:|TestListClass | Clr | Clr | 5.599 us | 0.0408 us | 0.0382 us | 5.561 us | 5.689 us | 5.583 us | 3 | - | 0 B |TestArrayClass | Clr | Clr | 2.024 us | 0.0102 us | 0.0096 us | 2.011 us | 2.043 us | 2.022 us | 2 | - | 0 B |TestListStruct | Clr | Clr | 8.427 us | 0.1983 us | 0.2204 us | 8.101 us | 9.007 us | 8.374 us | 5 | - | 0 B |TestArrayStruct | Clr | Clr | 1.539 us | 0.0295 us | 0.0276 us | 1.502 us | 1.577 us | 1.537 us | 1 | - | 0 B |TestLinqClass | Clr | Clr | 13.117 us | 0.1007 us | 0.0892 us | 13.007 us | 13.301 us | 13.089 us | 7 | 0.0153 | 80 B |TestLinqStruct | Clr | Clr | 28.676 us | 0.1837 us | 0.1534 us | 28.441 us | 28.957 us | 28.660 us | 9 | - | 96 B |TestListClass | Core | Core | 5.747 us | 0.1147 us | 0.1275 us | 5.567 us | 5.945 us | 5.756 us | 4 | - | 0 B |TestArrayClass | Core | Core | 2.023 us | 0.0299 us | 0.0279 us | 1.990 us | 2.069 us | 2.013 us | 2 | - | 0 B |TestListStruct | Core | Core | 8.753 us | 0.1659 us | 0.1910 us | 8.498 us | 9.110 us | 8.670 us | 6 | - | 0 B |TestArrayStruct | Core | Core | 1.552 us | 0.0307 us | 0.0377 us | 1.496 us | 1.618 us | 1.552 us | 1 | - | 0 B |TestLinqClass | Core | Core | 14.286 us | 0.2430 us | 0.2273 us | 13.956 us | 14.678 us | 14.313 us | 8 | 0.0153 | 72 B |TestLinqStruct | Core | Core | 30.121 us | 0.5941 us | 0.5835 us | 28.928 us | 30.909 us | 30.153 us | 10 | - | 88 B |
代码:
[RankColumn, MinColumn, MaxColumn, StdDevColumn, MedianColumn][ClrJob, CoreJob][HtmlExporter, MarkdownExporter][MemoryDiagnoser]public class BenchmarkRef{public class C1{public string Text1;public string Text2;public string Text3;}
public struct S1{public string Text1;public string Text2;public string Text3;}
List<C1> testListClass = new List<C1>();List<S1> testListStruct = new List<S1>();C1[] testArrayClass;S1[] testArrayStruct;public BenchmarkRef(){for(int i=0;i<1000;i++){testListClass.Add(new C1 { Text1= i.ToString(), Text2=null, Text3= i.ToString() });testListStruct.Add(new S1 { Text1 = i.ToString(), Text2 = null, Text3 = i.ToString() });}testArrayClass = testListClass.ToArray();testArrayStruct = testListStruct.ToArray();}
[Benchmark]public int TestListClass(){var x = 0;foreach(var i in testListClass){x += i.Text1.Length + i.Text3.Length;}return x;}
[Benchmark]public int TestArrayClass(){var x = 0;foreach (var i in testArrayClass){x += i.Text1.Length + i.Text3.Length;}return x;}
[Benchmark]public int TestListStruct(){var x = 0;foreach (var i in testListStruct){x += i.Text1.Length + i.Text3.Length;}return x;}
[Benchmark]public int TestArrayStruct(){var x = 0;foreach (var i in testArrayStruct){x += i.Text1.Length + i.Text3.Length;}return x;}
[Benchmark]public int TestLinqClass(){var x = testListClass.Select(i=> i.Text1.Length + i.Text3.Length).Sum();return x;}
[Benchmark]public int TestLinqStruct(){var x = testListStruct.Select(i => i.Text1.Length + i.Text3.Length).Sum();return x;}}
如果你有一个array of structs,则数组本身就是堆上的对象,并且数组中包含结构值。因此garbage collector只有一个对象需要考虑。如果数组超出范围,垃圾回收器可以一步释放数组内的所有结构。如果您的代码的任何其他部分使用此数组中的结构,则由于结构被复制,我们可以安全地释放数组本身及其内容。
如果你有一个array of objects,数组本身和数组中的每个对象都是堆上的单独对象。每个对象都可以存储在堆的完全不同的部分,你的代码的另一部分可能有对这些对象的引用。所以当我们的数组超出范围时,我们不能马上释放数组。因为the garbage collector必须单独考虑每个对象,并确保在释放它们之前没有对每个对象的引用。