Pracuję nad symulacją płynów w języku C#. Każdy cykl muszę obliczyć prędkość płynu w dyskretnych punktach w przestrzeni. W ramach tych obliczeń potrzebuję kilkudziesięciu kilobajtów na przestrzeń scratch, aby pomieścić kilka podwójnych tablic [] (dokładny rozmiar macierzy zależy od niektórych danych wejściowych). Tablice są potrzebne tylko na czas metody, która ich używa, i istnieje kilka różnych metod, które wymagają takiej przestrzeni.Scratch memory in managed environment
Jak ja to widzę, istnieje kilka różnych rozwiązań do budowy tablic podstaw:
Wykorzystanie „nowe”, aby pobrać z pamięci sterty każdym razem, gdy wywoływana jest metoda. To właśnie robiłem na początku, jednak wywiera ona duży nacisk na śmieciarza, a kilka-ms pików raz lub dwa razy na sekundę jest naprawdę denerwujące.
Przygotuj tablice rysunkowe jako parametry podczas wywoływania metod. Problem polega na tym, że zmusza użytkownika do zarządzania nimi, w tym do odpowiedniego ich doboru, co jest ogromnym problemem. A to sprawia, że korzystanie z mniej lub bardziej porysowanej pamięci jest trudne, ponieważ zmienia interfejs API.
Użyj stosu alokacji w niebezpiecznym kontekście, aby przydzielić pamięć scratch ze stosu programów. To działałoby dobrze, z wyjątkiem tego, że musiałbym skompilować się z/unsafe i ciągle kropić niebezpieczne bloki w całym kodzie, czego chciałbym uniknąć.
Przydzielać prywatne tablice raz podczas uruchamiania programu. To jest w porządku, ale niekoniecznie znam rozmiar tablic, których potrzebuję, dopóki nie spojrzę na niektóre dane wejściowe. I robi się naprawdę nieporządnie, ponieważ nie można ograniczyć zakresu tych prywatnych zmiennych do jednej metody, więc stale zanieczyszczają przestrzeń nazw. I skaluje się słabo, ponieważ liczba metod, które wymagają pamięci na zarysowania, wzrasta, ponieważ przydzielam dużo pamięci, która była używana tylko przez ułamek czasu.
Utwórz pewną pulę centralną i przydzielaj tablice pamięci scratch z puli. Głównym problemem jest to, że nie widzę łatwego sposobu przydzielania dynamicznie wielkości macierzy z puli centralnej. Mógłbym użyć przesunięcia początkowego i długości i mieć całą pamięć podstawową w zasadzie współdzielić pojedynczą dużą tablicę, ale mam dużo istniejącego kodu, który zakłada podwójne [] s. I musiałbym być ostrożny, aby taki wątek był bezpieczny.
...
Czy ktoś ma jakieś doświadczenia z podobnym problemem? Wszelkie porady/lekcje do zaoferowania z doświadczenia?
Czy naprawdę miałeś na myśli kilka dziesiątków kilobajtów? Ponieważ jest to tak mała ilość, nie martwiłbym się o zarządzanie pamięcią ... –
To nie brzmi zbyt dobrze, ale jeśli mam 2000 cykli/sekundę, nagle jest to około 60 MB/s, i GC zaczyna zauważać. –
@JayLemmon, myślę, że dbasz o te szczegóły ze względu na wydajność, prawda? Jeśli twój projekt się nie zakończył, sugeruję, żebyś nie przejmował się wydajnością aż do końca. Zobacz ten artykuł na temat [Przedwczesna optymalizacja] (http://c2.com/cgi/wiki?PrematureOptimization). Jeśli projekt jest skończony, artykuł zawiera ciekawe spostrzeżenia również na temat __optymalizacji__ w ogóle. Cytuję część: "Częstym błędnym przekonaniem jest to, że zoptymalizowany kod jest z konieczności bardziej skomplikowany [...] lepszy, dobrze napisany kod często działa szybciej i zużywa mniej pamięci [...]". – jay