02. Performance Comparison between Structure and Class

It will take about 3 minutes to finish reading this article.

As we all know that, Since struct instances are allocated on stack, and class instances are allocated on heap, structs can sometimes be drastically faster.
So there is an example here can prove that.

Consider the following example, which demonstrates 2 strategies of wrapping Int data type using struct and class. Using 10 repeated values are to better reflect real world, where you have multiple fields.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// 1 field 
class IntClass {
let value: Int
init(_ val: Int) { self.value = val }
}

struct IntStruct {
let value: Int
init(_ val: Int) { self.value = val }
}

func + (x: IntClass, y: IntClass) -> IntClass {
return IntClass(x.value + y.value)
}

func + (x: IntStruct, y: IntStruct) -> IntStruct {
return IntStruct(x.value + y.value)
}
// 10 fields
class Int10Class {
let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int

init(_ val: Int) {
self.value1 = val
self.value2 = val
self.value3 = val
self.value4 = val
self.value5 = val
self.value6 = val
self.value7 = val
self.value8 = val
self.value9 = val
self.value10 = val
}
}

struct Int10Struct {
let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int

init(_ val: Int) {
self.value1 = val
self.value2 = val
self.value3 = val
self.value4 = val
self.value5 = val
self.value6 = val
self.value7 = val
self.value8 = val
self.value9 = val
self.value10 = val
}
}

func + (x: Int10Struct, y: Int10Struct) -> Int10Struct {
return Int10Struct(x.value1 + y.value1)
}

func + (x: Int10Class, y: Int10Class) -> Int10Class {
return Int10Class(x.value1 + y.value1)
}

Performance is measured using:
Tests.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Tests {
static func runTests() {
print("Running tests")

measure("class (1 field)") {
var x = IntClass(0)
for _ in 1...10000000 {
x = x + IntClass(1)
}
}

measure("struct (1 field)") {
var x = IntStruct(0)
for _ in 1...10000000 {
x = x + IntStruct(1)
}
}

measure("class (10 fields)") {
var x = Int10Class(0)
for _ in 1...10000000 {
x = x + Int10Class(1)
}
}

measure("struct (10 fields)") {
var x = Int10Struct(0)
for _ in 1...10000000 {
x = x + Int10Struct(1)
}
}
}

static private func measure(_ name: String, block: @escaping () -> ()) {
print()
print("\(name)")
let t0 = CACurrentMediaTime()

block()

let dt = CACurrentMediaTime() - t0
print("\(dt)")
}
}

We can find somewhere in our project and just run the following code:

1
Tests.runTests()

One of my running results is as follows:

1
2
3
4
5
6
7
8
9
10
11
class (1 field)
6.262335019011516

struct (1 field)
3.954203129003872

class (10 fields)
6.161917756006005

struct (10 fields)
4.097320644999854

We can find that ‘struct’ type is more faster than ‘class’ type.

Reference

[1] Why Choose Struct Over Class?