CPU & Memory Performance Flashcards

(64 cards)

1
Q

What is something that is stored automatically on the heap and not the stack?

A

Anything with the “new” keyword in C#

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What is the stack?

A

It is the region of memory used for storing local variables, method calls, and function parameters.

It works in a Last In, First Out (LIFO) way—meaning the last item pushed on is the first one popped off.

It is used automatically by the runtime when methods are called and exited. For example, each time a method is called, a new “stack frame” is created for its variables.

Stack memory is fast but limited in size, and it’s cleared automatically when a method exits.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

The role of the garbage collector is to …

A

Deallocate dereferenced objects on the heap

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What is the heap?

A

It is the region of memory used for storing objects and data that need to live beyond the scope of a method call.

Unlike the stack, the heap is not automatically cleared—instead, the Garbage Collector (GC) cleans it up when objects are no longer used.

Data on the heap is accessed via references (pointers), and allocating memory here is slower than on the stack, but it allows for longer-lived and larger objects.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

What are the main ways memory is added to the heap?

A

Memory is added to the heap mainly when you use the new keyword to create objects, arrays, or strings.

Reference types (like classes, arrays, and strings) are always stored on the heap.
Value types (like int, bool, struct) go on the heap only when they’re part of a reference type (e.g., inside a class or boxed).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Which of the following .NET types is NOT a value type?

A) int
B) bool
C) string
D) double

A

A: ✅ C) string

string is a reference type in .NET, even though it behaves somewhat like a value type because it’s immutable.

All the other options (int, bool, double) are value types, which are stored directly on the stack (unless boxed).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

What is the difference between a value and reference type?

A

Value Type
- Stores the actual data directly.
- Typically stored on the stack.
- Copied when assigned to a new variable or passed to a method.

Examples: int, bool, double, struct.

Reference Type
- Stores a reference (pointer) to the data, not the data itself.
- Data is stored on the heap.
- Multiple variables can point to the same object in memory.

Examples: string, class, array, object.

Key Difference:
Assigning a value type creates a copy, but assigning a reference type creates a shared reference.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

A reference type variable does not contain an object, but instead only holds a reference to an object where?

A

On the heap.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Two reference type variables can refer to the same object on the heap.

True or False

A

True

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Reference types are assigned by reference. What does this mean?

A

When a reference type is assigned to another variable, both variables point to the same object in memory (the reference is copied).

This means changes made through one variable will affect the same object seen by the other.

class Person { public string Name; }

var a = new Person { Name = “Alice” };
var b = a;
b.Name = “Bob”;

Console.WriteLine(a.Name);
// Output: “Bob”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

How much memory does any reference take?

A

A reference (the pointer to an object on the heap) typically takes:

4 bytes on a 32-bit system

8 bytes on a 64-bit system

This is because a reference is just an address pointing to the object’s location in memory, and its size depends on the architecture of the system (32-bit vs 64-bit).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

class Person { public string Name; }

// Why are these not considered equal?
var a = new Person { Name = “Alice” };
var b = new Person { Name = “Alice” };

Console.WriteLine(a == b); // False

A

Because a and b are reference types, the == operator checks if they refer to the same object in memory, not whether their contents are equal.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Boxing happens when …..

a) A variable of type ‘object’ is cast to a reference type.

b) A variable of type ‘object’ is cast to a value type.

c) Storing a reference type in a variable of type ‘object’.

d) Storing a value type in a variable of type ‘object’.

A

d) Storing a value type in a variable of type ‘object’.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Unboxing happens when…

A

a variable of type ‘object’ (which holds a boxed value type) is explicitly converted back to its original value type.

class Person { public int Age; }
var a = new Person {Age = 20 };
var age = (int)a.Age;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What is the primary difference in portability between CIL (Common Intermediate Language) and Assembly Language?

A

CIL is platform-independent, meaning it can run on any system with the .NET Common Language Runtime (CLR). Assembly Language is platform-dependent, specific to a particular CPU architecture (e.g., x64, ARM).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What component in the .NET ecosystem is responsible for converting CIL into native machine code that the CPU can execute?

A

The Just-In-Time (JIT) compiler, which is part of the Common Language Runtime (CLR).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Does Assembly Language directly control hardware, or does it rely on a virtual machine?

A

Assembly Language directly controls hardware, using instructions that the CPU executes natively. It does not rely on a virtual machine.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

When you compile C# code, what language does it first get translated into?

A

It first gets translated into CIL (Common Intermediate Language).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

What benefit does .NET gain by compiling to CIL first, rather than directly to Assembly Language?

A

It gains platform independence and managed execution. CIL allows .NET applications to run on different CPU architectures without recompilation, and the CLR provides services like garbage collection and type safety.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Strings are immutable in .NET. What does this mean?

A

Once a string object is created, its value cannot be changed. Any operation that appears to modify a string actually creates a new string object in memory with the new value, leaving the original string unchanged.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Why is immutable strings is useful?

A

It allows for super-fast assignment and comparing of strings.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

When is using the StringBuilder preferred?

A

StringBuilder is preferred when you anticipate performing a significant number of string modifications (like appending, inserting, or replacing characters/sub-strings) because string objects are immutable, leading to inefficient memory allocation and performance issues with repeated modifications. StringBuilder is mutable and more efficient for such scenarios.

For strings, every dereferenced string will be left for the GC to clean up, but if using a StringBuilder, the GC only need to clean up the one object.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

With strings, what is “interning” and why is it useful?

A

Interning is a process where the .NET runtime stores a single, unique copy of each literal string (and optionally, other strings) in a special memory area called the “intern pool.” It’s useful because it saves memory and allows for faster string comparisons.

So if two variables are “intern” the same large paragraph, the compiler reuses the reference for both. When they are compared, only the reference is compared. On a x64 operating system, this is an 8 byte comparison.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

Strings are reference types but behave like value types.

True or False

A

True

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
At a high level, how is the StringBuilder implemented that allows it to not use immutable string under the hood?
It uses a char array and buffer with capacity. Strings appended are turned into chars.
26
What is the "Call Stack" (or "Execution Stack" / "Program Stack") ?
It's used for managing method calls (function calls). When a method is called, a new stack frame (also known as an activation record) is pushed onto the call stack. When a method finishes executing, its stack frame is popped off the call stack, and execution returns to the caller.
27
What is the "Evaluation Stack" (or "Operand Stack") ?
It is internal to the Common Language Runtime (CLR) and is specifically used during the execution of CIL (Intermediate Language) instructions. It's a temporary workspace for performing computations and storing intermediate results as CIL instructions are executed.
28
What is a system classes that uses the object array that harms performance?
System.Collections.Specialized - ArrayList - ColectionBase - DictionaryBase - HashTable - Queue - SortedList - Stack - HybridDictionary - ListDictionary - OrderedDictionary System.Data - DataSet - DataTable - DataRow // DataRow uses object arrays internally for storing data // for performance, refactor to DataReader instead
29
What system class library is better for performance to stay away from object arrays (object arrays require boxing and unboxing values) ?
System.Collections.Generics - Dictionary - HashSet - LinkedList - List - Queue - List - SortedDictionary - SortedList - SortedSet - Stack // Generic collections use typed arrays for storing data
30
Code with BOX and UNBOX instructions is up to 5 times slower with the same code without these instructions True of False
True
31
When is using simple ADD "+" operator with strings faster than using the StringBuilder, and can you explain why?
Normally, up to 4 "+" to a string is faster than using a StringBuilder. This is because the initial capacity management is optimized for many appends. It still has to manage its internal buffer and capacity. The StringBuilder.ToString() at the end to get your final string object involves another memory allocation and a copy operation from StringBuilder's internal buffer to the new string object.
32
Why is var array = new int[numOfElems]; for (int i = 0; i < numOfElems; i++) { } always faster than var list = new List(numOfElems); for (int i = 0; i < numOfElems; i++) { }
Because the CIL has built in support for arrays.
33
What is a good way to make a decision on when to use an arrays and generic lists?
- use an array if you have mission critical code and the number of elements is known - use a generic list if you have mission critical code and the number of elements is not known - avoid classes in System.Collections because they use object arrays and requires boxing and unboxing
34
can you name the fastest to slowest arrays? and explain why? a) var oneDimensionalArray = new int[x * y]; b) var twoDimensionalArray = new int[x,y]; c) var cSharpJaggedArray = new int[x][y];
a) - 1st - var oneDimensionalArray = new int[x * y]; c) - 2nd - var cSharpJaggedArray = new int[x][y]; b) - 3rd - var twoDimensionalArray = new int[x,y]; The 1st place is the fastest because the CIL has built in support for arrays. That makes 1st and 2nd place options close but because a) pre-allocates the its capacity with 1 operation, this gives it the edge over c). 2nd place is close to option a) but it will need to loop over the entire outer array and pre-allocate its capacity for every inner array. 3rd place is called a "jagged array" and it does not have built-in support with the CIL. It's basically a class that will require more operations that anything that does not have built in support.
35
What is a good thought processes for deciding which array to use - one dimensional array int[a * b] - two dimensional array int[a,b] - jagged array int[a][b]
- if you have only 1 dimension of data, use 1-dimensional array for best performance - if you have 2 dimensions of data, flatten the array - if this is not possible consider using a jagged array arr[a][b] - as a last resort, use a 2 dimensional array arr[a,b]
36
Why should we use `int.TryParse(numStr, out result);` over a try catch int.Parse like try { int.Parse(numStr); } catch(Exception ex) { }
Basically, exceptions are expensive and eat of a lot of cpu and memory. The .TryParse() does not throw Exceptions and is much more performant that simply throwing exceptions.
37
What is a good thought systems for using Exceptions?
- use excpetions for fatal conditions that require an abort - don't put try-catch blocks in deeply nested code - never use catch(Exception) to catch all exceptions - do not use exceptions for non-critical conditions - never use exceptions to control the flow of your program
38
Should you refactor to use a for over a foreach loop when - using a generic list? why or why not? - using a built-in array? why or why not?
for a built-in array type, the for loop is marginally faster and not worth the refactor for generic list, for loops are 1.6x faster generally than foreach loops bonus: try and use an array over a list for 2.5x the performance
39
When using a foreach loop to loop through a collection of value types, why should you always make sure to get an IEnumerable interface instead of a non-generic IEnumerable interface?
To prevent the undesired boxing and unboxing of each collection item.
40
What is the generation 0 in the Small Object Heap?
Purpose: This is where newly allocated objects are initially placed. Behavior: Gen 0 collections are very frequent and very fast. The GC assumes that most objects created here will die quickly (e.g., local variables, temporary objects), so it only checks this small area frequently. If an object survives a Gen 0 collection, it gets promoted to Gen 1.
41
What is the generation 1 in the Small Object Heap?
Purpose: This generation acts as an intermediate holding area for objects that survived a Gen 0 collection. Behavior: Collections in Gen 1 are less frequent than Gen 0. If an object survives a Gen 1 collection, it gets promoted to Gen 2.
42
What is the generation 2 in the Small Object Heap?
Purpose: This generation holds long-lived objects that have survived multiple collections in Gen 0 and Gen 1. This includes objects like static fields, long-lived data structures, or UI elements that persist throughout the application's lifetime. Behavior: Gen 2 collections are the least frequent but the most expensive (they involve checking the entire managed heap). A Gen 2 collection also implies that Gen 0 and Gen 1 are collected as well.
43
What is the difference between the Small Object Heap and the Large Object Heap?
SOH: Fast, frequent, compacting collections for small, often short-lived objects. LOH: Less frequent, non-compacting collections for large objects, trading potential fragmentation for reduced movement overhead. Only has 1 gen that works like gen 2 in the SOH.
44
What is the size that determines if an object will go into the LOH?
85 kilobytes
45
What are the 3 cycle phases of the GC in dotnet?
1) Mark 2) Sweep 3) Compact
46
What is the Mark cycle phase in the dotnet GC?
The GC looks at everything your program is currently actively using or can still reach. It starts from things like variables you've defined, objects on your screen, etc. It then "marks" all these important, "live" objects. It's like putting a sticky note on everything you want to keep. Goal: To identify everything that is not marked, which is trash.
47
What is the Sweep cycle phase in the dotnet GC?
The GC then goes through the entire memory space. Any object that doesn't have a "sticky note" (wasn't marked as live) is considered trash. The GC "sweeps" these dead objects away, meaning it frees up the memory they were taking up, making that space available again. Goal: To reclaim memory from dead objects.
48
What is the Compact cycle phase in the dotnet GC?
After sweeping, you might have lots of small "holes" of free space scattered around (like gaps on a shelf after you remove some items). In the compact phase, the GC slides all the "sticky-noted" (live) objects closer together, filling in those holes. It's like pushing all the books together on a shelf to make one big empty space. Goal: To reduce memory fragmentation and create larger, contiguous blocks of free space, making it easier and faster to allocate new objects. (Note: This usually happens on the Small Object Heap, not so much on the Large Object Heap).
49
What is the strategy called Object Pooling?
Object pooling is an optimization strategy where, instead of creating new objects from scratch, you reuse objects from a pre-initialized "pool" to prevent the GC from having to clean up more unreferenced memory than needed.
50
Which is considered managed memory and why: stack or heap?
The Heap is considered managed memory. The Garbage Collector (GC) is responsible for automatically managing memory on the Heap, determining when objects are no longer in use and reclaiming their space. In contrast, memory on the Stack is automatically managed by the CPU and the .NET runtime, with its lifetime tied directly to the method that created it, so there's no need for the GC to manage it.
51
Why would you want to use pointers for manipulating images in c#?
The image data stored on the PC is in unmanaged memory. The images are almost always too large for any other type of high level access.
52
Is the below code creating a reference or is it copying the value over in the assignment? int a = 5; int b = a;
It's copies the value over because ints are value types. int a = 5; int b = a; b += 1; Console.WriteLine(a); // 5 Console.WriteLine(b); // 6
53
What is the output of the below code and why? class Person { public string Name {get;set;} } var personA = new Person() { Name = "John" }; var personB = personA; personB.Name = "Sally"; Console.WriteLine(personA.Name); Console.WriteLine(personB.Name);
Console.WriteLine(personA.Name); // Sally Console.WriteLine(personB.Name); // Sally In C#, class definitions create reference types. This means that when you create an instance of Person (e.g., new Person()), the variable doesn't directly hold the object itself. Instead, it holds a reference (think of it like a pointer or an address) to where that Person object is stored on the Heap.
54
When two reference types are compared, what is being compared? var personA = new Person() { Name = "John" }; var personB = new Person() { Name = "John" }; Console.WriteLine(personA == personB);
Console.WriteLine(personA == personB); // False What's being compared is the reference, not the value. Since both personA and personB hold two different reference on the heap, the comparison between the two will evaluate to false.
55
What is a Finalizer in C#? (Sometimes mistakenly called a "Deconstructor" by those coming from C++)
A Finalizer is a special method declared using a tilde (~) before the class name (e.g., ~MyClass() { /* cleanup code */ }). It runs when it is being Garbage Collected. The ~ on the Deconstructor tells the .NET runtime to put the method in the "Finalizer Queue" which will run when the dereference class is "Garbage Collected."
56
What are some rules for using "Finalizers" ?
- you cannot make any assumptions about the "order" objects will be finalized. - you should never try to use a referenced object in your finalizer, because it might already be finalized. - try to stay away from using Finalizers at a root object and instead, if you have to, use only finalizers at edge references
57
What are some downsides to using "Finalizers" ?
They force the reference into at least Gen 1, making them live possibly longer than needed. This causes more copy operations as well, when the GC runs a compact operation. So they take up more CPU cycles when the object could've been collected in Gen 0. - they are called in random order - they are not guaranteed to be called. This especially happens when the process exits where they are only given a max of 4 seconds to run before the program is exited.
58
The .NET garbage collector automatically compacts the large object heap (LOH) when it gets fragmented. And why or why not? True or False
False Small Object Heap (SOH) (Generations 0, 1, 2): These are compacted regularly by the GC to reduce fragmentation and improve allocation speed. Large Object Heap (LOH): Not compacted by default due to the high performance cost. It relies on a free list to reuse available space. You can force a one-time compaction if needed, but it's not automatic.
59
Your code contains lots of large (>= 85 KB) short-lived objects. What should you do?
Instead of creating new large objects and letting them be garbage collected, you "pool" them. When you need a large object, you try to get one from the pool. When you're done, you return it to the pool instead of letting it go out of scope. The benefit is significantly reduces GC pressure on the LOH, prevents fragmentation.
60
In C#, how are strings optimized for comparison?
C# strings are optimized for comparison through a feature called string interning. When string literals (strings defined directly in your code, like "Hello") are compiled or loaded, the .NET runtime often stores only one unique copy of each distinct string value in a special pool. If multiple variables refer to the exact same string literal value, they can all point to this single, interned object in memory. This means that for identical string literals, a simple and very fast reference equality check (comparing if two variables point to the same memory location) can be performed using the == operator, rather than a more expensive character-by-character comparison.
61
What is a struct in C# and why should you use them?
They are a value type, meaning its is typically allocated on the stack rather than on the managed heap. When you assign a struct to another variable or pass it to a method, a copy of the entire data is made, not just a reference. You should use structs for small, lightweight data types that represent a single value. They can offer performance benefits by reducing garbage collection overhead (since they're not on the heap) and improving memory locality, especially when you have many instances of them. However, they should generally be immutable and kept small, as copying large structs can become expensive.
62
What is a record in C# and why should you use them?
A record in C# is a special kind of reference type (by default, though record struct exists) primarily designed for modeling immutable data. Its key superpower is value equality, where two records are considered equal if all their public properties have the same values. You should use records when you need to represent data-centric types where immutability is desired, and you want automatic value equality comparisons. They're excellent for data transfer objects (DTOs) or representing state that shouldn't change after creation.
63
What are some basic reasons to use structs?
- use structs when the data you're storing represents a single value - use structs if you data size if very small (24 bytes or less) and you are going to create thousands or millions of instances - use structs if your data is immutable - use structs if your data will not have to be boxed frequently Otherwise, just use classes
64
What are the methods for an IEnumerable? And what are the methods of a IEnumerator?
IEnumerable - GetEnumerator() IEnumerator - Current - MoveNext() - Reset()