Scripting: Automatic Reference Counting – Arma Reforger
Lou Montana (talk | contribs) m (Fix Wikipedia link) |
mNo edit summary |
||
| (7 intermediate revisions by 2 users not shown) | |||
| Line 1: | Line 1: | ||
{{TOC|side}} | |||
'''Automatic Reference Counting''', shortened to '''ARC''', is a memory management solution used in Enforce Script. Enforce Script does not use Garbage Collection (a.k.a GC). | '''Automatic Reference Counting''', shortened to '''ARC''', is a memory management solution used in Enforce Script. Enforce Script does not use Garbage Collection (a.k.a GC). | ||
<!-- | <!-- | ||
| Line 21: | Line 22: | ||
* it is simple to implement (having a good working GC is a big issue) | * it is simple to implement (having a good working GC is a big issue) | ||
On the negative side, it is open to the cyclic reference problem, described in the {{Link|#Cyclic Reference}} paragraph below. | |||
{{Feature|informative|This whole system impacts '''objects''' passed by '''reference''' - see | {{Feature|informative|This whole system impacts '''objects''' passed by '''reference''' - see {{Link|Arma Reforger:Scripting: Values#Types|Value Types}}.}} | ||
| Line 29: | Line 30: | ||
Enfusion has an internal counter of strong references to objects; when this counter reaches 0, the object is released from memory. | Enfusion has an internal counter of strong references to objects; when this counter reaches 0, the object is released from memory. | ||
{{Feature|warning|Reference only makes sense with <enforce inline>Managed</enforce> objects; using {{hl|ref}} with a ''value type'' (e.g <enforce inline>ref vector</enforce> or <enforce inline>ref int</enforce>) is incorrect!}} | |||
=== Strong Reference === | === Strong Reference === | ||
A strong reference is a reference to an object that increments the reference counter. The referenced object '''cannot''' become null during the | A strong reference is a reference to an object that increments the reference counter. | ||
The referenced object '''cannot''' become null during the referencing object's lifetime unless manually deleted (with the {{hl|[[Arma Reforger:Scripting: Keywords#delete|delete]]}} keyword). | |||
{{Feature|important| | |||
Strong references: | Strong references: | ||
* using the {{hl|[[Arma Reforger:Scripting: Keywords#ref|ref]]}} keyword | * using the {{hl|[[Arma Reforger:Scripting: Keywords#ref|ref]]}} keyword | ||
* scope lifetime's script reference | * scope lifetime's script reference | ||
References to local variables in methods are already strong, so using <enforce inline>ref</enforce> in methods is redundant: | |||
{{{!}} class{{=}}"wikitable" | |||
! Do | |||
! Don't | |||
{{!}}- | |||
{{!}} <enforce> | |||
void Method(int a, int b, int c) | |||
{ | |||
array<int> numbers = { a, b, c }; // yes | |||
foreach (int number : numbers) | |||
{ | |||
Print(number); | |||
} | |||
} | |||
</enforce> | |||
{{!}} <enforce> | |||
void Method(int a, int b, int c) | |||
{ | |||
ref array<int> numbers = { a, b, c }; // no | |||
foreach (int number : numbers) | |||
{ | |||
Print(number); | |||
} | |||
} | |||
</enforce> | |||
{{!}}} | |||
}} | |||
=== Weak Reference === | === Weak Reference === | ||
| Line 85: | Line 117: | ||
// arrayOfWeakRef is destroyed (it only contains NULL), | // arrayOfWeakRef is destroyed (it only contains NULL), | ||
// arrayOfStrongRef is destroyed (it contains the last strong ref to object, so its contained object is destroyed as well | // arrayOfStrongRef is destroyed (it contains the last strong ref to object, so its contained object is destroyed as well | ||
} | } | ||
} | } | ||
</enforce> | </enforce> | ||
| Line 106: | Line 138: | ||
class Parent | class Parent | ||
{ | { | ||
ref Child | ref Child m_Child; | ||
} | } | ||
class Child | class Child | ||
{ | { | ||
ref Parent | ref Parent m_Parent; | ||
} | } | ||
void | void Function() | ||
{ | { | ||
Parent a = new Parent(); // 'a' has 1 reference | Parent a = new Parent(); // 'a' has 1 reference | ||
Child b = new Child(); // 'b' has 1 reference | Child b = new Child(); // 'b' has 1 reference | ||
a. | a.m_Child = b; // 'b' has 2 references | ||
b. | b.m_Parent = a; // 'a' has 2 references | ||
// local variables 'a', 'b' are released (reference count is decreased by 1) | // local variables 'a', 'b' are released (reference count is decreased by 1) | ||
// both objects remain in memory, having 1 reference each (each other) | // both objects remain in memory, having 1 reference each (each other) | ||
} | } | ||
</enforce> | </enforce> | ||
| Line 131: | Line 163: | ||
class Parent | class Parent | ||
{ | { | ||
ref Child | ref Child m_Child; | ||
} | } | ||
class Child | class Child | ||
{ | { | ||
Parent | Parent m_Parent; | ||
} | } | ||
void | void Function() | ||
{ | { | ||
Parent a = new Parent(); // 'a' has 1 strong (scope) reference | Parent a = new Parent(); // 'a' has 1 strong (scope) reference | ||
Child b = new Child(); // 'b' has 1 strong (scope) reference | Child b = new Child(); // 'b' has 1 strong (scope) reference | ||
a. | a.m_Child = b; // 'b' has 2 strong references | ||
b. | b.m_Parent = a; // 'a' has 1 strong reference, 1 weak reference | ||
// local variables 'a', 'b' are released (reference count is decreased by 1) | // local variables 'a', 'b' are released (reference count is decreased by 1) | ||
// a only has 1 weak reference and is released from memory | // a only has 1 weak reference and is released from memory | ||
// b loses a's reference and has no more reference to it - it gets released | // b loses a's reference and has no more reference to it - it gets released | ||
} | } | ||
</enforce> | </enforce> | ||
Using weak references makes null-checking take more importance in scripting. | Using weak references makes null-checking take more importance in scripting. | ||
{{GameCategory|armaR|Modding|Guidelines | {{GameCategory|armaR|Modding|Scripting|Guidelines}} | ||
Latest revision as of 16:12, 26 February 2026
Automatic Reference Counting, shortened to ARC, is a memory management solution used in Enforce Script. Enforce Script does not use Garbage Collection (a.k.a GC). In comparison with the widely used Tracing garbage collection (in e.g C#, Java):
- it does not suffer from cleanup stuttering (lags due to high GC load)
- memory management performance is not dependent on the number of managed instances
- it is simple to implement (having a good working GC is a big issue)
On the negative side, it is open to the cyclic reference problem, described in the Cyclic Reference paragraph below.
Principle
Enfusion has an internal counter of strong references to objects; when this counter reaches 0, the object is released from memory.
Strong Reference
A strong reference is a reference to an object that increments the reference counter. The referenced object cannot become null during the referencing object's lifetime unless manually deleted (with the delete keyword).
Weak Reference
A weak reference is a reference to an object that does not increment the reference counter. The reference may become null during the program's lifetime.
Usage
Cyclic Reference
Problem
The main issue with reference counting is cyclic references (aka "Island of isolation"). In the code below:
- the main method creates object A and object B
- object A references object B
- object B references object A
- the main method ends, dropping its references to object A and B
- both objects a and b should be deleted but they still reference each other, keeping the reference counting above 0:
- any reference to them is lost after main method's ending
- they remain in memory until the program is stopped
Solution
The solution to this issue is to have one object have a strong reference, while the other only holds a weak one:
Using weak references makes null-checking take more importance in scripting.