Udostępnij za pośrednictwem


Hostowanie i wdrażanie aplikacji po stronie Blazor serwera

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ostrzeżenie

Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz .NET i .NET Core Support Policy (Zasady obsługi platformy .NET Core). Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

W tym artykule wyjaśniono, jak hostować i wdrażać aplikacje po stronie Blazor serwera (Blazor Web Appi Blazor Server aplikacje) przy użyciu platformy ASP.NET Core.

Wartości konfiguracji hosta

Aplikacje po stronie Blazor serwera mogą akceptować ogólne wartości konfiguracji hosta.

Wdrożenie

Użycie modelu Blazor hostingu po stronie serwera jest wykonywane na serwerze z poziomu aplikacji ASP.NET Core. Aktualizacje interfejsu użytkownika, obsługa zdarzeń i wywołania języka JavaScript są obsługiwane za pośrednictwem SignalR połączenia.

Wymagany jest serwer internetowy obsługujący aplikację ASP.NET Core. Program Visual Studio zawiera szablon projektu aplikacji po stronie serwera. Aby uzyskać więcej informacji na Blazor temat szablonów projektów, zobacz ASP.NET Core project structure (Struktura projektu ASP.NET CoreBlazor).

Opublikuj aplikację w konfiguracji wydania i wdróż zawartość bin/Release/{TARGET FRAMEWORK}/publish folderu, w {TARGET FRAMEWORK} którym symbol zastępczy jest platformą docelową.

Skalowalność

Biorąc pod uwagę skalowalność pojedynczego serwera (skalowanie w górę), pamięć dostępna dla aplikacji jest prawdopodobnie pierwszym zasobem, który aplikacja wyczerpała w miarę wzrostu zapotrzebowania użytkownika. Dostępna pamięć na serwerze ma wpływ na:

  • Liczba aktywnych obwodów, które może obsługiwać serwer.
  • Opóźnienie interfejsu użytkownika na kliencie.

Aby uzyskać wskazówki dotyczące tworzenia bezpiecznych i skalowalnych aplikacji po stronie Blazor serwera, zobacz następujące zasoby:

Każdy obwód używa około 250 KB pamięci dla minimalnej aplikacji hello world stylu. Rozmiar obwodu zależy od kodu aplikacji i wymagań dotyczących konserwacji stanu skojarzonych z każdym składnikiem. Zalecamy mierzenie zapotrzebowania na zasoby podczas opracowywania aplikacji i infrastruktury, ale następujący punkt odniesienia może stanowić punkt początkowy planowania celu wdrożenia: Jeśli oczekujesz, że aplikacja będzie obsługiwać 5000 współbieżnych użytkowników, rozważ budżetowanie co najmniej 1,3 GB pamięci serwera do aplikacji (lub ok. 273 KB na użytkownika).

Konfiguracja widoku SignalR

SignalRWarunki hostingu i skalowania mają zastosowanie do Blazor aplikacji korzystających z programu SignalR.

Aby uzyskać więcej informacji na SignalR temat aplikacji, w Blazor tym wskazówek dotyczących konfiguracji, zobacz wskazówki dotyczące platformy ASP.NET CoreBlazorSignalR.

Transporty

Blazor działa najlepiej w przypadku korzystania z obiektów WebSocket jako SignalR transportu ze względu na mniejsze opóźnienia, lepszą niezawodność i lepsze zabezpieczenia. Długie sondowanie jest używane, SignalR gdy zestawy WebSocket nie są dostępne lub gdy aplikacja jest jawnie skonfigurowana do korzystania z długiego sondowania.

Jeśli jest używane długie sondowanie, zostanie wyświetlone ostrzeżenie konsoli:

Nie można nawiązać połączenia za pośrednictwem obiektów WebSocket przy użyciu transportu rezerwowego Long Polling. Może to być spowodowane blokowaniem połączenia przez sieć VPN lub serwer proxy.

Globalne błędy wdrażania i połączenia

Zalecenia dotyczące wdrożeń globalnych w centrach danych geograficznych:

  • Wdróż aplikację w regionach, w których większość użytkowników mieszka.
  • Weź pod uwagę zwiększone opóźnienie ruchu na różnych kontynentach. Aby kontrolować wygląd interfejsu użytkownika ponownego łączenia, zobacz wskazówki ASP.NET CoreBlazorSignalR.
  • Rozważ użycie usługi platformy AzureSignalR.

Azure App Service

Hosting w usłudze aplikacja systemu Azure wymaga konfiguracji obiektów WebSocket i koligacji sesji, nazywanej również koligacją routingu żądań aplikacji (ARR).

Uwaga

Blazor Aplikacja w usłudze aplikacja systemu Azure nie wymaga usługi platformy AzureSignalR.

Włącz następujące informacje dotyczące rejestracji aplikacji w usłudze aplikacja systemu Azure Service:

  • Protokoły WebSocket umożliwiające działanie transportu obiektów WebSocket. Domyślne ustawienie to Wyłączone.
  • Koligacja sesji w celu kierowania żądań od użytkownika z powrotem do tego samego wystąpienia usługi App Service. Ustawienie domyślne to Włączone.
  1. W witrynie Azure Portal przejdź do aplikacji internetowej w usłudze App Services.
  2. Otwórz pozycję Konfiguracja ustawień>.
  3. Ustaw pozycję Gniazda internetowe na wartość Włączone.
  4. Sprawdź, czy koligacja sesji jest ustawiona na włączone.

Usługa platformy Azure SignalR

Opcjonalna usługa platformy Azure SignalR działa w połączeniu z centrum aplikacji SignalR w celu skalowania aplikacji w górę aplikacji po stronie serwera do dużej liczby współbieżnych połączeń. Ponadto globalne zasięg usługi i centra danych o wysokiej wydajności znacznie pomagają zmniejszyć opóźnienia ze względu na lokalizację geograficzną.

Usługa nie jest wymagana w przypadku Blazor aplikacji hostowanych w usłudze aplikacja systemu Azure Lub Azure Container Apps, ale może być przydatna w innych środowiskach hostingu:

  • Aby ułatwić skalowanie połączeń w poziomie.
  • Obsługa dystrybucji globalnej.

Uwaga

Stanowe ponowne połączenie (WithStatefulReconnect) zostało wydane za pomocą platformy .NET 8, ale nie jest obecnie obsługiwane dla usługi platformy Azure SignalR . Aby uzyskać więcej informacji, zobacz Stateful Reconnect Support? (Obsługa ponownego łączenia stanowego? (Azure/azure-signalr #1878).

W przypadku, gdy aplikacja używa długiego sondowania lub wraca do długiego sondowania zamiast obiektów WebSocket, może być konieczne skonfigurowanie maksymalnego interwału sondowania (MaxPollIntervalInSecondsdomyślnie: 5 sekund, limit: 1–300 sekund), który definiuje maksymalny interwał sondowania dozwolony dla połączeń długich sondowania w usłudze Platformy Azure SignalR . Jeśli następne żądanie sondowania nie zostanie dostarczone w maksymalnym interwale sondowania, usługa zamknie połączenie klienta.

Aby uzyskać wskazówki dotyczące dodawania usługi jako zależności do wdrożenia produkcyjnego, zobacz Publikowanie aplikacji ASP.NET Core SignalR w usłudze aplikacja systemu Azure Service.

Aby uzyskać więcej informacji, zobacz:

Azure Container Apps

Aby dowiedzieć się więcej na temat skalowania aplikacji po stronie Blazor serwera w usłudze Azure Container Apps, zobacz Scaling ASP.NET Core Apps on Azure (Skalowanie aplikacji ASP.NET Core Apps na platformie Azure). W tym samouczku wyjaśniono, jak tworzyć i integrować usługi wymagane do hostowania aplikacji w usłudze Azure Container Apps. Podstawowe kroki są również dostępne w tej sekcji.

  1. Skonfiguruj usługę Azure Container Apps pod kątem koligacji sesji, postępując zgodnie ze wskazówkami w temacie Koligacja sesji w usłudze Azure Container Apps (dokumentacja platformy Azure).

  2. Usługa ASP.NET Core Data Protection (DP) musi być skonfigurowana do utrwalania kluczy w scentralizowanej lokalizacji, do których mogą uzyskiwać dostęp wszystkie wystąpienia kontenerów. Klucze mogą być przechowywane w usłudze Azure Blob Storage i chronione za pomocą usługi Azure Key Vault. Usługa DP używa kluczy do deserializacji Razor składników. Aby skonfigurować usługę DP do korzystania z usług Azure Blob Storage i Azure Key Vault, zapoznaj się z następującymi pakietami NuGet:

    Uwaga

    Aby uzyskać instrukcje dodawania pakietów do aplikacji .NET, zobacz artykuły w sekcji Instalowanie pakietów i zarządzanie nimi w temacie Przepływ pracy użycia pakietów (dokumentacja programu NuGet). Sprawdź prawidłowe wersje pakietów pod adresem NuGet.org.

  3. Zaktualizuj Program.cs za pomocą następującego wyróżnionego kodu:

    using Azure.Identity;
    using Microsoft.AspNetCore.DataProtection;
    using Microsoft.Extensions.Azure;
    
    var builder = WebApplication.CreateBuilder(args);
    var BlobStorageUri = builder.Configuration["AzureURIs:BlobStorage"];
    var KeyVaultURI = builder.Configuration["AzureURIs:KeyVault"];
    
    builder.Services.AddRazorPages();
    builder.Services.AddHttpClient();
    builder.Services.AddServerSideBlazor();
    
    builder.Services.AddAzureClientsCore();
    
    builder.Services.AddDataProtection()
                    .PersistKeysToAzureBlobStorage(new Uri(BlobStorageUri),
                                                    new DefaultAzureCredential())
                    .ProtectKeysWithAzureKeyVault(new Uri(KeyVaultURI),
                                                    new DefaultAzureCredential());
    var app = builder.Build();
    
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    
    app.UseRouting();
    
    app.UseAuthorization();
    
    app.MapRazorPages();
    
    app.Run();
    

    Powyższe zmiany umożliwiają aplikacji zarządzanie usługą DP przy użyciu scentralizowanej, skalowalnej architektury. DefaultAzureCredential Odnajduje aplikację kontenera zarządzaną identity po wdrożeniu kodu na platformie Azure i używa jej do łączenia się z magazynem obiektów blob i magazynem kluczy aplikacji.

  4. Aby utworzyć zarządzaną identity aplikację kontenera i udzielić jej dostępu do magazynu obiektów blob i magazynu kluczy, wykonaj następujące kroki:

    1. W witrynie Azure Portal przejdź do strony przeglądu aplikacji kontenera.
    2. Wybierz pozycję Łącznik usługi w obszarze nawigacji po lewej stronie.
    3. Wybierz pozycję + Utwórz z górnej nawigacji.
    4. W menu wysuwany Tworzenie połączenia wprowadź następujące wartości:
      • Kontener: wybierz utworzoną aplikację kontenera do hostowania aplikacji.
      • Typ usługi: wybierz pozycję Blob Storage.
      • Subskrypcja: wybierz subskrypcję, która jest właścicielem aplikacji kontenera.
      • Nazwa połączenia: wprowadź nazwę scalablerazorstorage.
      • Typ klienta: wybierz pozycję .NET , a następnie wybierz przycisk Dalej.
    5. Wybierz pozycję Zarządzany identity przez system i wybierz pozycję Dalej.
    6. Użyj domyślnych ustawień sieciowych i wybierz pozycję Dalej.
    7. Po zweryfikowaniu ustawień przez platformę Azure wybierz pozycję Utwórz.

    Powtórz powyższe ustawienia dla magazynu kluczy. Wybierz odpowiednią usługę i klucz magazynu kluczy na karcie Podstawy .

IIS

W przypadku korzystania z usług IIS włącz:

Aby uzyskać więcej informacji, zobacz wskazówki i zewnętrzne linki do zasobów usług IIS w temacie Publikowanie aplikacji ASP.NET Core w usługach IIS.

Kubernetes

Utwórz definicję ruchu przychodzącego z następującymi adnotacjami Kubernetes dla koligacji sesji:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: <ingress-name>
  annotations:
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "affinity"
    nginx.ingress.kubernetes.io/session-cookie-expires: "14400"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "14400"

System Linux z serwerem Nginx

Postępuj zgodnie ze wskazówkami dotyczącymi aplikacji ASP.NET Core SignalR z następującymi zmianami:

  • Zmień ścieżkę location z /hubroute (location /hubroute { ... }) na ścieżkę / główną (location / { ... }).
  • Usuń konfigurację buforowania serwera proxy (proxy_buffering off;), ponieważ ustawienie ma zastosowanie tylko do zdarzeń wysłanych przez serwer (SSE), które nie są istotne dla Blazor interakcji między klientem aplikacji a serwerem.

Aby uzyskać więcej informacji i wskazówek dotyczących konfiguracji, zapoznaj się z następującymi zasobami:

System Linux z serwerem Apache

Aby hostować aplikację za platformą Blazor Apache w systemie Linux, skonfiguruj ProxyPass ruch HTTP i WebSocket.

W poniższym przykładzie:

  • Kestrel serwer jest uruchomiony na maszynie hosta.
  • Aplikacja nasłuchuje ruchu na porcie 5000.
ProxyPreserveHost   On
ProxyPassMatch      ^/_blazor/(.*) http://localhost:5000/_blazor/$1
ProxyPass           /_blazor ws://localhost:5000/_blazor
ProxyPass           / http://localhost:5000/
ProxyPassReverse    / http://localhost:5000/

Włącz następujące moduły:

a2enmod   proxy
a2enmod   proxy_wstunnel

Sprawdź konsolę przeglądarki pod kątem błędów obiektów WebSocket. Przykładowe błędy:

  • Firefox nie może nawiązać połączenia z serwerem pod adresem ws://the-domain-name.tld/_blazor?id=XXX
  • Błąd: Nie można uruchomić transportu "WebSockets": Błąd: Wystąpił błąd podczas transportu.
  • Błąd: Nie można uruchomić transportu "LongPolling": TypeError: this.transport jest niezdefiniowany
  • Błąd: Nie można nawiązać połączenia z serwerem z żadnym z dostępnych transportów. Nie można uruchomić obiektów WebSocket
  • Błąd: Nie można wysłać danych, jeśli połączenie nie znajduje się w stanie "Połączono".

Aby uzyskać więcej informacji i wskazówek dotyczących konfiguracji, zapoznaj się z następującymi zasobami:

Mierzenie opóźnienia sieci

JS Interop może służyć do mierzenia opóźnienia sieci, jak pokazano w poniższym przykładzie.

MeasureLatency.razor:

@inject IJSRuntime JS

<h2>Measure Latency</h2>

@if (latency is null)
{
    <span>Calculating...</span>
}
else
{
    <span>@(latency.Value.TotalMilliseconds)ms</span>
}

@code {
    private DateTime startTime;
    private TimeSpan? latency;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            startTime = DateTime.UtcNow;
            var _ = await JS.InvokeAsync<string>("toString");
            latency = DateTime.UtcNow - startTime;
            StateHasChanged();
        }
    }
}
@inject IJSRuntime JS

<h2>Measure Latency</h2>

@if (latency is null)
{
    <span>Calculating...</span>
}
else
{
    <span>@(latency.Value.TotalMilliseconds)ms</span>
}

@code {
    private DateTime startTime;
    private TimeSpan? latency;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            startTime = DateTime.UtcNow;
            var _ = await JS.InvokeAsync<string>("toString");
            latency = DateTime.UtcNow - startTime;
            StateHasChanged();
        }
    }
}
@inject IJSRuntime JS

<h2>Measure Latency</h2>

@if (latency is null)
{
    <span>Calculating...</span>
}
else
{
    <span>@(latency.Value.TotalMilliseconds)ms</span>
}

@code {
    private DateTime startTime;
    private TimeSpan? latency;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            startTime = DateTime.UtcNow;
            var _ = await JS.InvokeAsync<string>("toString");
            latency = DateTime.UtcNow - startTime;
            StateHasChanged();
        }
    }
}
@inject IJSRuntime JS

<h2>Measure Latency</h2>

@if (latency is null)
{
    <span>Calculating...</span>
}
else
{
    <span>@(latency.Value.TotalMilliseconds)ms</span>
}

@code {
    private DateTime startTime;
    private TimeSpan? latency;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            startTime = DateTime.UtcNow;
            var _ = await JS.InvokeAsync<string>("toString");
            latency = DateTime.UtcNow - startTime;
            StateHasChanged();
        }
    }
}
@inject IJSRuntime JS

@if (latency is null)
{
    <span>Calculating...</span>
}
else
{
    <span>@(latency.Value.TotalMilliseconds)ms</span>
}

@code {
    private DateTime startTime;
    private TimeSpan? latency;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            startTime = DateTime.UtcNow;
            var _ = await JS.InvokeAsync<string>("toString");
            latency = DateTime.UtcNow - startTime;
            StateHasChanged();
        }
    }
}

W przypadku rozsądnego środowiska interfejsu użytkownika zalecamy trwałe opóźnienie interfejsu użytkownika 250 ms lub mniej.

Zarządzanie pamięcią

Na serwerze jest tworzony nowy obwód dla każdej sesji użytkownika. Każda sesja użytkownika odpowiada renderowaniu pojedynczego dokumentu w przeglądarce. Na przykład wiele kart tworzy wiele sesji.

Blazorutrzymuje stałe połączenie z przeglądarką, nazywane obwodem, które zainicjowało sesję. Połączenia można utracić w dowolnym momencie z kilku powodów, takich jak utrata łączności sieciowej przez użytkownika lub nagłe zamknięcie przeglądarki. W przypadku utraty połączenia ma mechanizm odzyskiwania, Blazor który umieszcza ograniczoną liczbę obwodów w puli "rozłączone", co daje klientom ograniczony czas ponownego nawiązywania połączenia i ponowne ustanawianie sesji (ustawienie domyślne: 3 minuty).

Po tym czasie Blazor zwalnia obwód i odrzuca sesję. Od tego momentu obwód kwalifikuje się do odzyskiwania pamięci (GC) i jest zgłaszany, gdy zostanie wyzwolona kolekcja dla generowania GC obwodu. Ważnym aspektem, który należy zrozumieć, jest to, że obwody mają długi okres istnienia, co oznacza, że większość obiektów zakorzenionych przez obwód ostatecznie osiągnie gen 2. W związku z tym te obiekty mogą nie być widoczne, dopóki kolekcja 2. generacji nie zostanie zwolniona.

Mierzenie ogólnego użycia pamięci

Wymagania wstępne:

  • Aplikacja musi zostać opublikowana w konfiguracji wydania . Pomiary konfiguracji debugowania nie są istotne, ponieważ wygenerowany kod nie jest reprezentatywny dla kodu używanego do wdrożenia produkcyjnego.
  • Aplikacja musi działać bez dołączonego debugera, ponieważ może to również mieć wpływ na zachowanie aplikacji i zepsuć wyniki. W programie Visual Studio uruchom aplikację bez debugowania, wybierając pozycję Debuguj>start bez debugowania na pasku menu lub Ctrl+F5 za pomocą klawiatury.
  • Rozważ różne typy pamięci, aby zrozumieć, ile pamięci jest rzeczywiście używane przez platformę .NET. Ogólnie rzecz biorąc, deweloperzy sprawdzają użycie pamięci aplikacji w Menedżerze zadań w systemie operacyjnym Windows, który zazwyczaj oferuje górną granicę rzeczywistej pamięci w użyciu. Aby uzyskać więcej informacji, zapoznaj się z następującymi artykułami:

Użycie pamięci zastosowane do Blazor

Obliczamy pamięć używaną w blazor następujący sposób:

(Obwody aktywne × pamięci obwodu) + (Odłączone obwody × pamięci obwodu)

Ilość pamięci używanej przez obwód oraz maksymalne potencjalne aktywne obwody, które może obsługiwać aplikacja, zależy w dużej mierze od sposobu pisania aplikacji. Maksymalna liczba możliwych aktywnych obwodów jest w przybliżeniu opisana przez:

Maksymalna ilość dostępnej pamięci / = na obwód maksymalna liczba potencjalnych aktywnych obwodów

Aby wyciek pamięci wystąpił w Blazorpliku , muszą być spełnione następujące warunki:

  • Pamięć musi być przydzielona przez strukturę, a nie aplikację. Jeśli przydzielisz tablicę o pojemności 1 GB w aplikacji, aplikacja musi zarządzać usuwaniem tablicy.
  • Pamięć nie może być aktywnie używana, co oznacza, że obwód nie jest aktywny i został wykluczony z pamięci podręcznej odłączonych obwodów. Jeśli masz uruchomione maksymalne aktywne obwody, brak pamięci jest problemem ze skalowaniem, a nie przeciekiem pamięci.
  • Uruchomiono odzyskiwanie pamięci (GC) dla generacji GC obwodu, ale moduł odśmiecywania pamięci nie był w stanie przejąć obwodu, ponieważ inny obiekt w strukturze posiada silne odwołanie do obwodu.

W innych przypadkach nie ma przecieku pamięci. Jeśli obwód jest aktywny (podłączony lub odłączony), obwód jest nadal używany.

Jeśli kolekcja dla generacji GC obwodu nie zostanie uruchomiona, pamięć nie zostanie zwolniona, ponieważ moduł odśmiecnia pamięci nie musi w tym czasie zwolnić pamięci.

Jeśli kolekcja dla generacji GC jest uruchamiana i zwalnia obwód, musisz zweryfikować pamięć względem statystyk GC, a nie proces, ponieważ platforma .NET może zdecydować się zachować aktywną pamięć wirtualną.

Jeśli pamięć nie zostanie zwolniona, musisz znaleźć obwód, który nie jest aktywny lub odłączony i jest zakorzeniony przez inny obiekt w strukturze. W każdym innym przypadku brak możliwości zwolnienia pamięci to problem z aplikacją w kodzie dewelopera.

Zmniejszanie użycia pamięci

Zastosuj dowolną z następujących strategii, aby zmniejszyć użycie pamięci aplikacji:

  • Ogranicz łączną ilość pamięci używanej przez proces platformy .NET. Aby uzyskać więcej informacji, zobacz Opcje konfiguracji środowiska uruchomieniowego dla odzyskiwania pamięci.
  • Zmniejsz liczbę odłączonych obwodów.
  • Zmniejsz czas, przez jaki obwód może znajdować się w stanie odłączenia.
  • Ręczne wyzwalanie odzyskiwania pamięci w celu wykonania kolekcji w okresach przestojów.
  • Skonfiguruj odzyskiwanie pamięci w trybie stacji roboczej, który agresywnie wyzwala odzyskiwanie pamięci zamiast trybu serwera.

Rozmiar sterty dla niektórych przeglądarek urządzeń przenośnych

Podczas kompilowania aplikacji uruchamianej Blazor na kliencie i docelowych przeglądarkach urządzeń przenośnych, zwłaszcza w przeglądarce Safari w systemie iOS, może być wymagana maksymalna ilość pamięci dla aplikacji z właściwością EmccMaximumHeapSize MSBuild. Aby uzyskać więcej informacji, zobacz Host and deploy ASP.NET Core Blazor WebAssembly.

Dodatkowe działania i zagadnienia

  • Przechwyć zrzut pamięci procesu, gdy zapotrzebowanie na pamięć jest wysokie i zidentyfikuj, że obiekty zajmują najwięcej pamięci i gdzie są one zakorzenione (co zawiera odwołanie do nich).
  • Możesz sprawdzić statystyki dotyczące zachowania pamięci w aplikacji przy użyciu polecenia dotnet-counters. Aby uzyskać więcej informacji, zobacz Badanie liczników wydajności (dotnet-counters).
  • Nawet w przypadku wyzwolenia GC platforma .NET przechowuje w pamięci zamiast natychmiast zwracać ją do systemu operacyjnego, ponieważ prawdopodobnie będzie ponownie używać pamięci w najbliższej przyszłości. Pozwala to uniknąć ciągłego zatwierdzania i dekomunikowania pamięci, co jest kosztowne. Zobaczysz to odzwierciedlone, jeśli używasz dotnet-counters , ponieważ wystąpią kontrolery domeny, a ilość używanej pamięci spadnie do 0 (zero), ale nie zobaczysz spadku licznika zestawu roboczego, co oznacza, że platforma .NET trzyma się w pamięci w celu ponownego użycia. Aby uzyskać więcej informacji na temat ustawień pliku projektu (.csproj), aby kontrolować to zachowanie, zobacz Opcje konfiguracji środowiska uruchomieniowego dla odzyskiwania pamięci.
  • Funkcja GC serwera nie wyzwala odzyskiwania pamięci, dopóki nie określi, że jest to absolutnie konieczne, aby uniknąć zamarzania aplikacji i uważa, że aplikacja jest jedyną rzeczą uruchomioną na maszynie, więc może używać całej pamięci w systemie. Jeśli system ma 50 GB, moduł odśmiecenia pamięci będzie używać pełnej 50 GB dostępnej pamięci, zanim wyzwoli kolekcję 2. generacji.
  • Aby uzyskać informacje na temat konfiguracji przechowywania odłączonego obwodu, zobacz wskazówki dotyczące ASP.NET CoreBlazorSignalR.

Mierzenie pamięci

  • Opublikuj aplikację w konfiguracji wydania.
  • Uruchom opublikowaną wersję aplikacji.
  • Nie dołączaj debugera do uruchomionej aplikacji.
  • Czy wyzwalanie wymuszonej, kompaktowanej kolekcji Gen 2 (GC.Collect(2, GCCollectionMode.Aggressive | GCCollectionMode.Forced, blocking: true, compacting: true)) zwalnia pamięć?
  • Rozważ, czy aplikacja przydziela obiekty na stercie dużych obiektów.
  • Czy testujesz wzrost pamięci po rozgrzaniu aplikacji przy użyciu żądań i przetwarzania? Zazwyczaj istnieją pamięci podręczne, które są wypełniane, gdy kod jest wykonywany po raz pierwszy, co zwiększa stałą ilość pamięci do śladu aplikacji.