.NET Memory - Heap Generations

Contents

Introduction

I last posted .NET Memory Management 101 where I talked about what value types were, what reference types were and showed that we can see them with a memory profiler like dotMemory.
This time we’ll look a bit more at the heap, specifically at generations.

Generations are used by the garbage collector to partition objects by how long it thinks they should live. It will then scan for objects to clean up more frequently in the sections that to thinks contains short lived objects.

Microsoft have a good introduction in their Fundamentals of Garbage Collection article.

We’re going to see if we can see in action again.

You can get the code for this example from my Git repository.

What are Generations?

According to the specifications there are three generations.

  1. Generation 0.
  2. Generation 1.
  3. Generation 2.

There’s the Large Object Heap. This is, as you can guess, for storing large objects; specifically, objects greater than 85Kb.

When an object is created it is put in generation 0. Generation 0 is for the shortest lived objects and gets the largest portion of the garbage collector’s attention. Objects are the promoted from generation 0 to generation 1 and generation 2 as the garbage collector determines it appropriate.

The question now is “How does the garbage collector decide when to promote an object?”. That bit is actually rather simple. If the garbage collector scans the object and finds that it is not ready for collection then it will promote it up to the next generation. It’s that simple.

Seeing it in action

What we’re going to do is quite simple. We’re just going to create object and watch it move up the generations as we call GC.Collect().

We have this very simple method that prints out the generation the object is in and the instructs the garbage collector to collect.

private static void GcCollect(object o)
{
    Console.WriteLine($"Object is in generation {GC.GetGeneration(o)}.");
    GC.Collect();
}

All we’re going to do is call this four times. We should see the object advance a generation until it gets to two and then stay there.

The full code is:

static void Main()
{
    var o = new object();

    var maxGeneration = GC.MaxGeneration;

    Console.WriteLine($"This environment has {maxGeneration} generations.");

    for (var i = 0; i < maxGeneration + 2; i++)
    {
        GcCollect(o);
    }
    Console.WriteLine("Finished...");
    Console.Read();
}

private static void GcCollect(object o)
{
    Console.WriteLine($"Object is in generation {GC.GetGeneration(o)}.");
    GC.Collect();
}

Currently, I think all the frameworks have 3 generations of memory. I might be wrong there, but there’s no harm in doing it right, even if it is a demo.

When we run the code we see the output we expect.

This environment has 2 generations.
Object is in generation 0.
Object is in generation 1.
Object is in generation 2.
Object is in generation 2.
Finished...

The object stayed in memory because I was using it in each iteration of the GcCollect(object) method. Once I am no longer using it to print out the message to the console the garbage collector will note that it there aren’t any references left and with collect it.

Weak References

We have a catch-22 here.

  1. We want to know if the object is garbage collected.
  2. To do this we need a reference to the object.
  3. If I have a reference to an object the garbage collector won’t collect it.
  4. GOTO 1

There is a solution though in the form of the WeakReference class.

A weak reference is a reference that the garbage collector should ignore when deciding whether an object is eligible for collection. We can use it here to hold a reference without preventing collection. We create a weak reference like so:

var weakReference = new WeakReference(o);

So, we’ll create one, run the GC. Then we’ll set o to be null so that there are no ‘strong’ references left and the GC should see it as collectable.

We’ll add the following to the previous code:

 var weak = new WeakReference(o);
 GC.Collect();
 Console.WriteLine($"Has o has been garbage collected? {(weak.IsAlive? "No" : "Yes")}");

The output confirm that the object is no longer alive.

Has o has been garbage collected? Yes

If we had other strong references to the object then the GC would not have collected the object.

Thanks for reading.

Feel free to contact me @BanksySan!

Visual Studio: Web Load Testing

Source code on my Git Repository.

Contents

Visual Studio Enterprise Edition has a project type called the Web Performance and Load Test Project.

New Project Screen showing Web Performance and Load Test Project

If you can’t see it then you probably just have to run the Visual Studio Installer and install it.

Install the Web Performance and Load Test Project components

Easy.

Running the Test Web Server

This is very easy!

If you clone the Git repository then you’ll see that as well as the Web Performance and Load Test Project there’s a console project too. The console project is a self hosting web server that we can use for running the web tests. If you run it without admin privileges (which is how you’re going to run it if you’re sensible) then it’ll throw a AutomaticUrlReservationCreationFailureException. In order to avoid this you’ll need to open the port it’s listening on. Assuming you’re using the default port of 9000 then you’ll need to run the following in a command prompt that is running as admin.

netsh http add urlacl url="http://+:9000}/" user="Everyone"

The web server lets you add messages, they’re saved in memory and can be retrieved either by ID or as a list of all of them.

Method Path Description
GET ~/ Return all messages
GET ~/{id} Get specific message
POST ~/{message} Store new message

Hello (Web Test) Word

Add a new item to the project and select ‘Web Performance Test…’ Annoyingly, it will assume that you want to record a test and start recording one for you and open IE for it too:

Empty Recording window

Anyhow, close it and click ‘Stop Recording’ and you’ll have an empty web test page where we can put our first web call.

Empty Web Test Page

To rename the test from boring ‘WebTest1’ to something useful like ‘HelloWorldTest’ we just change the name of the file. The test will update itself.

Now, we’ll get our first web request. Right-click on the node and select ‘Add Request’. It’ll create a request node pointing to http://localhost/. Right click and select ‘Properties’ (or press F4) and you’ll see the editable properties.

Web request properties

Here we can change the URL, the method and more. We’ll post a new message to our test server (get it running without debugging if it’s not).

Set the following properties:

Property Value
Url http://localhost:9000/hello-world
Method POST

Click the run button on the top left to run the test.

Run test button

All going well you should see a successful run like this:

Successful test run

NB: If you get a 404, check the test server is running

If you click on the test then the tabs underneath will contain details about the call:

  • Web Browser will attempt to render the response in a browser. In this case, it just shows the JSON we return {"Id": 1 }.
  • Request will give you some details about the request including headers, cookies, query string parameters and form parameters.
  • Response will give you the headers and body for the response.
  • Context isn’t important yet. It contains the variables for this test case.
  • Details gives you, well, other stuff.

Validating the Response

Go back to the web test again and right-click on the request node (the one with http://localhost:9000/hello-world). Select ‘Add Validation Rule’ from the context menu. You’ll be presented an ugly dialogue box with some validation options. We’re going for the very simplest here so select ‘Find Text’ and set the text to some random thing so that we can see the test fail before we see it pass.

Add Validation Rule dialogue box

You’ll see the validation rule appear. If we run the test then we’ll see it fail.

Now, to see what exactly went wrong you can click on the tabs. When you get to the ‘Details’ tab you’ll see what happened:

Rule Type Result Parameters
Find Text Validation The required text ‘Incorrect’ did not appear in the HTML response. FindText=Incorrect, IgnoreCase=False, UseRegularExpression=False, PassIfTextFound=True

Seems pretty conclusive. Let’s make it pass now, we’ll just hard code it to start with. My ID here is 2, so I know the next one will be 3 so I’ll set it to expect {"Id": 3 }.

When we run it again we get a pass. If we look in the details tab we can see the validation rule again, but passing this time.

Passing validation rule

That was fun, but we need to confirm that we can get the message as well. We could just get all the messages and search for what we want or we could get the inserted message by its ID and check it’s the same. Whichever we choose we’re going to need another web request. Right click the root node and select ‘Add Request’ again. You could select ‘Add Dependent Request’ here but, well, don’t.

You should now see another request like before. Change the properties to be:

Property Value
Url http://localhost:9000/4
Method GET

This should retrieve the message with ID 4 that we create when we run it this time.

You’ll also have to update the validation rule to expect {"Id": 4 } new or that will fail.

If you’ve done everything correctly then you’ll see the passing test.

Passing Test

Of course, this is useless as a load test as it isn’t re-runnable. Every time you run it you need to figure out what the next ID is and manually type it in. If that’s all you were planning on doing then use Fiddler instead.

Using variables (a.k.a. “Context Parameters”)

Context parameter are variable data that is scoped to a specific test. We can use them to store and retrieve data so that our tests are dynamic and re-runnable. We’re going to use one to store the ID of the created message and the message itself. This means that in the future we can run the test a lot of times, in parallel and do actual load testing.

First of all, lets add one. The only node you can add a context parameter to is the root node. This makes sense as context parameters are scoped to the whole test. Right click again and select ‘Add Context Parameter’. It’ll add a folder to keep all your context parameters same and give it the default name Parameter1 and no value. Create another one and use the properties to rename them and give them values.

Name Value
ID 5
Message hello-world

Now we’ll plug these parameters in. We reference a parameters with the parameter name in double parentheses. e.g.:

  • {{ID}}
  • {{Message}}

So, change the URLs for web requests to:

  • http://localhost:9000/{{Message}}
  • http://localhost:9000/{{ID}}

You’ll also have to change the test in our Validation Rule to include the token for the ID parameter:

{"Id": {{ID}} }

(Substitute the ID for whatever one you’re on now, I’m sure you’ve grasped this bit by now)

You should have something like this:

Context Parameters with replacement tokens in URL

Run the test and you’ll see that the values in the context parameters have replaced the tokens.

Passing Tests

We still have to manually update the ID, but at least it’s only in one place now. What we really want to be able to do is capture the ID from the initial POST and use that. The default extraction options are pretty rubbish, you can write custom ones but we’ll make to.

Right click on the first request and select ‘Add Extraction Rule’. Choose the ‘Extract Text’ option and enter the following values.

Property Name Value
Context Parameter Name ID
Starts With {"Id":
Ends With }
Required True
HTML Decode False

Your screen should look like this now.

Parameter Extraction

If we run it then it fails.

Test failing validation

If you click on the failed test and click on the details we can see what went wrong. It seems that the extraction worked but the validation is failing now. The reason it that the validation runs before the extraction runs. This isn’t great, there is a solution but it’s for a later date. Right now we’ll have to make do with using a regular expression to check that some integer is returned.

We can use this regex:

^\{\s*"Id"\s*:\s\d*\s*\}$

Now, run it again and we get a nice green test run.

Tests passing

Lastly, we have the message being sent being hard coded to hello-world. It would be nice if it could be tokenized too.

Using a Data Source

First we’ll create a CSV file as a data source. For the test driver to read the file the first line must contain the headers.

I’ve created a file called Messages.csv with the following content:

Messages
Lorem-ipsum-dolor
Sit-amet-a
Tortor-nec-nulla
A-lacinia-enim-felis-ut-sit
Sed-laoreet-etiam
Mi-sagittis-ut
Nulla-nec-fringilla-aptent
Justo-semper-volutpat
Justo-integer-architecto
Blandit-eum-pretium
Pellentesque-lobortis-nulla
Non-sit-qui
Maecenas-vivamus-at
Aliquam-consequat-pellentesque-sapien-ante-ultricies-proin

Right click on the root node again and select ‘Add Data Source’. You’ll be presented with a dialogue box. Name it ‘Messages’ and select ‘CSV File’ as the Data Source Type. Use the to browse to the file or just type in the path. You’ll see a sample of the content in the window. Click Finish.

Add file to project

Unless you’ve added the file to the project you’ll see a dialogue asking if you want to add it. Select ‘Yes’

Now you should have a screen like this:

With DataSource defined

Just to be different, change the ‘Access method’ property from ‘Sequential’ to ‘Random’.

The token for the value in the data source needs to be qualified and again in double parentheses.

{{DataSourceName.Filename#Extension.ColumnName}}

For us this is:

{{Messages.Messages#csv.Messages}}

Which means our original URL should now be:

http://localhost:9000/{{Messages.Messages#csv.Messages}}

Run this and you’ll see it pass with a random message taken from our CSV file.

Tests passing

Lastly, lets validate that the correct message is being returned. Add another validation rule, this time to the GET request. It’ll be a ‘Find Text’ validation rule again. Set the ‘Use Regular Expression’ property to True again and set the ‘Find Text’ value to

^\s*\{\s*"message"\s*:\s"{{Messages.Messages#csv.Messages}}"*\s*\}\s*$`

We don’t need the Message parameter at all any more, so you can delete it.

Our finished test should now look like:

Finished Hello World Web Test

Run it and you should see it all green again. Have a look in the details tabs to see the validations and extractions etc.

Using a Web Test as a Load Test

Finally, we’ll make this into a basic load test. The crude way it to just set the test to run a certain number of times. You can do this in by opening the local.testsettings file. It’s probably in the Solution Items folder. Double click it to open the edit dialogue.

local.testsettings

Click ‘Web Test’ and change the ‘Fixed Run Count’ to something bigger than 1 or select the ‘One run per data source row’.

Web Test settings dialogue

Save it.

Run the test again and you’ll see it runs many times.

Many test runs

I don’t know why the highlighting is so horrible in Visual Studio.

We don’t get many useful statistics here, we can copy everything to clipboard but all we get is:

Passed  Run 1               
Passed      http://localhost:9000/Non-sit-qui   200 OK  0.018 sec   0.018 sec   11
Passed      http://localhost:9000/31    200 OK  0.001 sec   0.001 sec   27
Passed  Run 2               
Passed      http://localhost:9000/Blandit-eum-pretium   200 OK  0.000 sec   0.000 sec   11
Passed      http://localhost:9000/32    200 OK  0.000 sec   0.000 sec   35
Passed  Run 3               
Passed      http://localhost:9000/Pellentesque-lobortis-nulla   200 OK  0.000 sec   0.000 sec   11
Passed      http://localhost:9000/33    200 OK  0.000 sec   0.000 sec   43
Passed  Run 4               
Passed      http://localhost:9000/Blandit-eum-pretium   200 OK  0.000 sec   0.000 sec   11
Passed      http://localhost:9000/34    200 OK  0.000 sec   0.000 sec   35
Passed  Run 5               
Passed      http://localhost:9000/A-lacinia-enim-felis-ut-sit   200 OK  0.000 sec   0.000 sec   11
Passed      http://localhost:9000/35    200 OK  0.000 sec   0.000 sec   43
Passed  Run 6               
Passed      http://localhost:9000/Lorem-ipsum-dolor 200 OK  0.000 sec   0.000 sec   11
Passed      http://localhost:9000/36    200 OK  0.000 sec   0.000 sec   33
Passed  Run 7               
Passed      http://localhost:9000/Lorem-ipsum-dolor 200 OK  0.000 sec   0.000 sec   11
Passed      http://localhost:9000/37    200 OK  0.000 sec   0.000 sec   33
Passed  Run 8               
Passed      http://localhost:9000/Non-sit-qui   200 OK  0.000 sec   0.000 sec   11
Passed      http://localhost:9000/38    200 OK  0.000 sec   0.000 sec   27
Passed  Run 9               
Passed      http://localhost:9000/Blandit-eum-pretium   200 OK  0.000 sec   0.000 sec   11
Passed      http://localhost:9000/39    200 OK  0.000 sec   0.000 sec   35
Passed  Run 10              
Passed      http://localhost:9000/Pellentesque-lobortis-nulla   200 OK  0.000 sec   0.000 sec   11
Passed      http://localhost:9000/40    200 OK  0.000 sec   0.000 sec   43

Let’s do something a bit more useful. Put the number of web test interactions back to 1.

We need to create a load test. The load will run the web test we created multiple times and generate statistics for you.

Right click on the project in the Solution Explorer and select ‘Add Load Test’. This will present you with another dialogue for you to define your test.

New Load Test Wizard

Here we can define run settings, like duration or iterations (I’m just going to choose 100 iterations).

We can also define our scenario, the scenario contains the individual tests to include, load patterns, number of users to simulate and details of how they’ll act along with other things you can see by clicking about.

I’m going to call the Scenario ‘Hello World’, give it five minutes duration, and a constant load of twenty five users.

In the ‘Test Mix’ we add the tests that will be included and can say what percentage of users will do what. We only have one test, so add that.

Web test added

Click ‘Finish’ and you’ll see the load test.

Load test

Now, after all that, you can click the run button. You’ll see a counter in the top right corner saying how much time is left. You’ll also see some graphs with performance metrics etc.. If you can’t see the graphs then you just need to click the ‘Graphs’ button.

Load test running

Errors

If you’re running this against the test server provided you’ll probably start seeing errors occurring. These are represented by the purple line in the top left graph for me. It might be different for you. You can see the legend at the bottom.

To see details of the errors click on the ‘Tables’ button.

Errors in table view

These are because by carefully crafted web server can’t handle this many users at once. The reason why? I’ll leave you to have a look at the code and see but I’ll give you a hint. Dictionary is not a thread-safe type for writing. Have a look at the MSDN reference.

Hope this was useful.

Thanks for reading.

Feel free to contact me @BanksySan!

Corrections always welcome (especially spelling mistakes).

.NET Memory Management 101

I watched an excellent video by Maarten Balliauw recently about dotMemory and the ClrMd framework and how .NET manages its memory.

I put up my crude notes in my previous post.

Here I thought I’d have a play myself and see what I can replicate myself. The source code is available in my Git repo.

Running it will give you four options for tests which we can use to see how objects and values are assigned in .NET.

Console menu

When you run a test there’ll be notifications of when to take a snapshot. Once you have, press Enter for the test to either continue of tell you it’s finished.

Reference Types & Value Types

The .NET framework has two main types, which it handles differently when it comes to memory management. These are:

  • Value type
  • Reference type

The key differences between the two from a coding perspective is that:

  Value Type Reference Type
Can be null? No Yes
Create new instance
on every method call
Yes No

Consider the following:

using System;

object referenceType = new object();
DateTime valueType = new DateTime(1, 2, 3);

public void AreTheyEqual(object o, DateTime d)
{
    Console.WriteLine("Reference types equal? {0}", referenceType == o);
    Console.WriteLine("Value types equal?     {0}", referenceType == o);
    Console.WriteLine("Reference types same?  {0}", Object.ReferenceEquals(o, referenceType));
    Console.WriteLine("Value types equal?     {0}", Object.ReferenceEquals(d, valueType));
}

AreTheyEqual(referenceType, valueType);

Try it on dotFiddle.

We create one value type and one reference type. We pass these into the method which then tests if they are equal using == and whether they’re actually the same thing with Object.ReferenceEquals().

The output is:

Reference types equal? True
Value types equal?     True
Reference types same?  True
Value types equal?     False

You can see that, whilst both the reference type and the value type equate as expected, the valuetype is not the same entity as that passed into it. This is because it has been copied whereas with the reference type we just passed a reference (pointer) to the existing object.

Stack and Heap

You will hear talk of the stack and the heap quite a bit. In fact, they’re technically just implementation details that are not guaranteed not to change (only the functional behaviours of the types is guaranteed).

“I find this characterization of a value type based on its implementation details rather than its observable characteristics to be both confusing and unfortunate. Surely the most relevant fact about value types is not the implementation detail of how they are allocated, but rather the by-design semantic meaning of “value type”, namely that they are always copied “by value”. If the relevant thing was their allocation details then we’d have called them “heap types” and “stack types”. But that’s not relevant most of the time. Most of the time the relevant thing is their copying and identity semantics.” - Eric Lippert

See:

Anyhow, in this case we are looking into under the hood of the memory management system (which is an implementation detail as well) as it makes sense for us to talk about stacks and heaps.

The Stack

The stack is where value types go!

Well, no, not exactly. It’s a good start though. The .NET primitives are all value types and, when a local variable, will sit on the stack along with references to objects in the heap.

Let’s have a look at the local primitives test. This simply creates a bunch of local integers with the values 0, 1, 2,… 49. An integer is a value type and as I just said, a local value type will be pushed onto the stack.

The code is very simple:

public void Start()
{
    _presenter.PromptForSnapshot();

    var i0 = RANDOM.Next();
    var i1 = RANDOM.Next();
    var i2 = RANDOM.Next();
    var i3 = RANDOM.Next();
    var i4 = RANDOM.Next();
    var i5 = RANDOM.Next();
    var i6 = RANDOM.Next();

    // Removed for space

    var i59 = RANDOM.Next();

    _presenter.PromptForSnapshot();
}

If we run the test and connect a memory profiler like dotMemory then we we can look at the heap before and after the variables are created. If you’re using dotMemory then you should have two snapshots taken and see similar to this:

Primitives Memory Usage

You can see that there’s no interesting activity recorded in the heap at all. All we can see if basic operating traffic by the application itself. There were 382 objects before we created the integers and 381 after. This is, of course, as expected. All the integers were added to the stack so don’t show the heap at all.

Why not put values on the heap?

Well, the heap it quite slow. When we add something to the stack we just write it in the next slot, then, when we are done we just move the pointer to where the framework will read from down. There are no clean up costs at all, the memory is just overwritten rather than reclaimed.

The Heap

All reference types end up in the head, with one or more references to them on the stack. As I’m sure you’re well aware strings are reference types despite the fact that, when coding we don’t need to use the new keyword.

If you run the program again and this time select the Strings option then we’ll see how these get stored.

The console will output:

Creating strings
================

----------------------------------------------------------------
Take a snapshot of the memory and press 'Enter' when you're done
----------------------------------------------------------------
Now we are going to create a set of 100 unique strings.

----------------------------------------------------------------
Take a snapshot of the memory and press 'Enter' when you're done
----------------------------------------------------------------
Now, we'll call the garbage collector

----------------------------------------------------------------
Take a snapshot of the memory and press 'Enter' when you're done
----------------------------------------------------------------
All done, have a look at the snapshots.

Done...

If you’ve created the snapshots in dotMemory you’ll see:
strings dotMemory

I’ve named the snapshots, yours might just be called Snapshot #1, Snapshot #2 etc.

You can see straight away from the snapshot boxes that 104 objects were created between the time the first snapshot was taken and the second. We expect that 100 of these will be the 100 strings we created, 1 will be the array holding them and the other two will ‘something else’. If we click on the compare we can see the details.

Compare before strings created to afterwards

If we filter on String then we can see that that 102 new strings were created and 1 new string array. So far, so good, we can see what the strings were.

String instances

There’s a lot of 90 byte strings there, they’ll be the ones we created for this test. The other two are:
* 124 bytes: "Now we are going to create a set of 100 unique strings."
* 16 bytes: "D"
These are for formatting the GUID into a string, and the text I write to the console.

If we compare the second and third snapshots now, after GC.Collect() was called, we can see that the objects have all been destroyed:

Strings destroyed

Conclusion

Reference types always go on the heap, local value types go on the stack. There is more to it than this, for example:

  • What happens to value types in reference types
  • What happens to reference type in value types?

Also, we’ve only shown that garbage collection cleans up unused references. The garbage collector does more than this too, but we’ll look at this in a future blog.

Hope you enjoyed this.

Thanks for reading.

Feel free to contact me @BanksySan!

dotMemoryNotes

Exploring NET’s Memory Management

A Trip Down Memory Lane

Hurriedly made notes from the “Exploring NET’s Memory Management A Trip Down Memory Lane” webcast.

GC

The garbage collector is part of the .NET runtime.
We compile to IL, the runtime compiles this to machine code. It handles type safety, security, threads and memory.

  • Virtually unlimited memory for our applications. You don’t have to consider memory allocation for the most part.
  • Big chunk of memory allocated when application starts. When we declare a variable it is added to this allocation.
  • The GC reclaims memory. Objects allocated in the managed heap. This makes it fast as it just adds a pointer.
  • .NET used some unmanaged memory for use itself.
  • GC releases objects no longer in use by examining application roots.
  • GC builds a graph of all the objects that are reachable from these roots. It takes time to scan these objects.
  • Generations
  • Large Object Heap.
  • The GC divides the heap into generations.
    • Gen-0: Short lived (e.g. local variable).
    • Gen-1: In-between’
    • Gen-2: Long-lived objects (e.g. Application’s main form).
  • When object scans, if it’s still needed it will promote the object to a higher generation.
  • Large Object Heap (LOH)
    • Special segment for large objects (>85Kb).
    • Collected only during full garbage collection.
    • Not compacted (by default)
    • Fragmentation can cause OutOfMemoryException.
  • When does GC run?
    • Out of memory condition.
    • After some ‘significant’ allocation.
    • Failure to allocate some native resource (internal to .NET).
    • Profiler - when triggered from the profiler API.
    • Forced - Call to System.GC.
    • Application moved to background.
  • GC pauses the running application to scan the heap.
  • Helping the GC. Use IDisposable & using.
  • Finalizers: BEWARE!! The object will move to the finalizer queue, which will always cause the object to be promoted a generation.
  • Weak references: Allow the GC to collect these objects.
    • Whenever the GC passes through it, it will be collected. Speeds up scan.

When is Memory Allocated?

  • Not for value types
    • Allocated on the stack.
  • Reference types.
    • new
    • “” (string.Empty)
  • Boxing.
  • Closures.
  • Param arrays.
  • … more.
  • How to see?
    • Resharper Heap Allocations Viewer plugin.
    • Roslyn’s Heap Allocation Analyzer.

GC

  • GC is optimised for high memory traffic in short lived objects.
  • *

Strings

  • Strings are objects.
    • Is actually a readonly collection of char.
  • String duplicates are normal.
    • .NET GC is fast.
    • They represent the balance on CUP v memory.
    • Gen-0 is nothing, gen-2 might be bad.

How can we tell is a string is a duplicate and is in the Intern Pool?

var a = "Hello World!";
var b = "Hello World!";

// a == b is true
// Object.ReferenceEquals(a, b) is true

Heap

  • Pointer to Run Time Type Information (RTTI)

clrMD

  • Open crash dumps or monitor running processes.

Thanks for reading.

Feel free to contact me @BanksySan!

Matrices

Introduction

OK, I admit, this is just an excuse to try out the LaTeX commands in StackEdit and see if they render nicely in Blogger (the blogging site previously known as BlogSpot). So, let’s get into it:

What is a Matrix?

Effectively, it’s just a multi-dimensional array of numbers. It’s commonly used to represent vectors in cartesian space.

Often matrices are represented by bold capital letters. e.g.:

Addition

Adding and subtracting matrices isn’t too different to adding scalar numbers. To add matrices together, they must be the same shape. That means the same number of rows and columns.

If we wanted to add together the following:

We’d just add each number to it’s corresponding number in the other matrix.

Subtracting is exactly the same, just subtract the numbers instead.

Important: Not all matrices can be added together. In order to add (or subtract) two matrices they must have the same dimensions.

E.g.:

Multiplication

Scalar Multiplication

Multiplying a matrix by a scalar is even more trivial than adding matrices together.

Multiplying two matrices

Multiplying matrices is a little more involved than addition and subtraction. We have to multiply each row in the first matrix with each column in the second matrix. Let’s start with two small matrices of size .

Multiplying each row on the left by each column on the right give us:

We can also multiply matrices of different dimensions:

Notice that has different sized dimensions than . This highlights some very important properties of matrix multiplication.

  • The the number of rows in is equal to the number of rows in and the number of columns is equal to the number of columns in .

More generally:

If we look at from above then we can compare them easier (without having to scroll up and down). We’ll rearrange the coefficients too to make it a bit clearer.

It’s now plain to see that:

  • Finally, the number of rows in must equal the number of columns there are in . If this is not the case then the result is undefined.