Turn Your Vehicle Into a Smart Earning Asset

While you’re not driving your car or bike, it can still be working for you. MOTOSHARE helps you earn passive income by connecting your vehicle with trusted renters in your city.

🚗 You set the rental price
🔐 Secure bookings with verified renters
📍 Track your vehicle with GPS integration
💰 Start earning within 48 hours

Join as a Partner Today

It’s simple, safe, and rewarding. Your vehicle. Your rules. Your earnings.

DOTNET: Memory Optimization in .NET with ValueTask

Here’s a single, self-contained console app that lets you experience the difference between:

  • 🚫 Without ValueTask – using async Task<int> (allocates a Task even on fast sync path)
  • With ValueTask – returning synchronously without allocating when value is cached

You’ll see timing + GC stats for both in the same run.


1️⃣ Full Code – Program.cs


This is <strong>100% self-contained</strong> – no extra packages needed.Code language: HTML, XML (xml)

2️⃣ Optional – Minimal .csproj

If you want to control the target framework explicitly, create ValueTaskDemo.csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>
Code language: HTML, XML (xml)

You can switch to net9.0 or net10.0 if you’re targeting .NET 9/10 SDK.


3️⃣ Step-by-Step: How to Run It

Step 1 – Create a new console project

dotnet new console -n ValueTaskDemo
cd ValueTaskDemo
Code language: JavaScript (javascript)

Step 2 – Replace Program.cs

  • Open Program.cs in your editor
  • Delete everything
  • Paste the full code from section 1️⃣

(Optionally replace the generated .csproj with the file in 2️⃣.)

Step 3 – Build and run in Release mode

dotnet run -c Release

You’ll see output similar to:

=========================================
   ValueTask Demo – Task vs ValueTask    
=========================================

Iterations : 5,000,000
Cache size : 1,000
Scenario   : All calls hit the FAST (cached) path.

Warming up (small runs)...
--- Warmup – async Task<int> ---
Iterations        : 500,000
Time Elapsed      : 80 ms
GC Gen0           : 10
GC Gen1           : 0
GC Gen2           : 0
Managed Memory Δ  : 3.20 MB
Checksum (ignore) : 499500000

--- Warmup – ValueTask<int> ---
Iterations        : 500,000
Time Elapsed      : 45 ms
GC Gen0           : 3
GC Gen1           : 0
GC Gen2           : 0
Managed Memory Δ  : 0.70 MB
Checksum (ignore) : 499500000

=========== REAL TESTS (Release) ==========

--- WITHOUT ValueTask – async Task<int> ---
Iterations        : 5,000,000
Time Elapsed      : 800 ms
GC Gen0           : 100
GC Gen1           : 5
GC Gen2           : 0
Managed Memory Δ  : 30.50 MB
Checksum (ignore) : 4995000000

--- WITH ValueTask – ValueTask<int> ---
Iterations        : 5,000,000
Time Elapsed      : 430 ms
GC Gen0           : 15
GC Gen1           : 0
GC Gen2           : 0
Managed Memory Δ  : 5.10 MB
Checksum (ignore) : 4995000000
Code language: HTML, XML (xml)

(Exact numbers will vary per machine, but the pattern should be similar.)


4️⃣ How to “Experience” and Interpret the Results

Focus on these for each scenario:

  • Time Elapsed
  • 🗑 GC Gen0 / Gen1 / Gen2
  • 💾 Managed Memory Δ

🔴 Scenario 1 – WITHOUT ValueTask (async Task)

public async Task<int> GetValueAsync(int key)
{
    if (_cache.TryGetValue(key, out var value))
    {
        return value; // looks sync, but method is async
    }

    await Task.Delay(1).ConfigureAwait(false);
    return key;
}
Code language: JavaScript (javascript)

Even when the value is immediately available in cache, the compiler:

  • Generates an async state machine
  • Allocates a Task object for each call

In a tight loop with millions of calls, you’ll see:

  • Higher Time Elapsed
  • More GC Gen0 collections
  • Higher Managed Memory Δ (more allocations)

🟢 Scenario 2 – WITH ValueTask (ValueTask)

public ValueTask<int> GetValueAsync(int key)
{
    if (_cache.TryGetValue(key, out var value))
    {
        return new ValueTask<int>(value); // completes synchronously, no Task allocation
    }

    return new ValueTask<int>(SlowPathAsync(key)); // real Task only on slow path
}
Code language: PHP (php)

Now:

  • For the fast path (cache hit), we:
    • Do not create a Task
    • Do not create a state machine
  • We only use a real Task<int> on the slow path (SlowPathAsync), which we’re not hitting in this benchmark.

In the output, you should see:

  • Lower elapsed time (less allocation + less GC work)
  • Much fewer Gen0 collections
  • Smaller Managed Memory Δ

This is exactly the use case where ValueTask shines:
A method that is often synchronous but must expose an async API.


5️⃣ Tweaks to Make the Effect More Visible

You can tune:

  • iterations (e.g., 10_000_000 if your machine is strong)
  • cacheSize (smaller cache keeps hit ratio at 100%)
const int iterations = 10_000_000;
const int cacheSize = 100;
Code language: JavaScript (javascript)

This increases the number of fast-path calls and magnifies the Task vs ValueTask difference.


Subscribe
Notify of
guest
0 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments

Certification Courses

DevOpsSchool has introduced a series of professional certification courses designed to enhance your skills and expertise in cutting-edge technologies and methodologies. Whether you are aiming to excel in development, security, or operations, these certifications provide a comprehensive learning experience. Explore the following programs:

DevOps Certification, SRE Certification, and DevSecOps Certification by DevOpsSchool

Explore our DevOps Certification, SRE Certification, and DevSecOps Certification programs at DevOpsSchool. Gain the expertise needed to excel in your career with hands-on training and globally recognized certifications.

0
Would love your thoughts, please comment.x
()
x