Twoim zadaniem jest wykrycie wycieku pamięci . Jest to program, który zużywa dużo pamięci, dopóki komputer się nie skończy i będzie musiał dokonać wymiany, aby uchronić się przed wyczerpaniem. Jedynym sposobem na zwolnienie pamięci jest zabicie programu w menedżerze zadań lub użycie zabójstwa z linii poleceń, takiego jak taskkill /im yourprogram /f
(w systemie Windows), a nawet ponowne uruchomienie komputera. Samo zamknięcie aplikacji nie powinno uniemożliwiać jej dalszego przechowywania pamięci.
Zasady:
Wszelkie bomby widłowe są zakazane. Oznacza to, że niesławna linia Bash
:(){ :|:&};:
jest zabroniona!Aplikacja musi być tylko jednowątkowa. Oznacza to zasadę bomby widelcowej.
Program nie może uruchamiać innych programów. Oznacza to, że nie możesz po prostu zrobić czegoś takiego
run(memoryfiller.exe)
. Jedynym wyjątkiem są programy dołączone do systemu operacyjnego lub języka, które nie są przeznaczone przede wszystkim do zużywania pamięci (tj. Mają inny cel). Oznacza to, że rzeczy takie jakcat
iln -s
są dozwolone.Możesz zająć tyle pamięci, ile chcesz. Im więcej tym lepiej.
Kod musi zostać w pełni wyjaśniony.
Powodzenia. To konkurs popularności, więc wygrywa kod z największą liczbą głosów po 10 dniach od daty zapytania!
źródło
while(1)malloc(999);
?Odpowiedzi:
Windows
Win32 API pozwala przydzielić pamięć w innych procesach, a następnie zdalnie odczytać / zapisać tę pamięć. Ten program ma tylko jeden wątek, którego używa do wyliczenia każdego uruchomionego procesu w systemie, a następnie kilkakrotnie przydziela 1 MB buforów w każdym procesie, dopóki alokacja nie powiedzie się. Po zakończeniu jednego procesu przechodzi do następnego. Alokacje nie są zwalniane po zakończeniu programu wywołującego - tylko wtedy, gdy / po zakończeniu każdego procesu docelowego. To zawiesza maszynę wirtualną z systemem Windows 7 o pojemności 2 GB w około 10 sekund. To wymaga uruchomienia jako administrator.
Kompilować:
cl /MD leak.cpp /link psapi.lib
źródło
Jawa
Wyjaśnienie
Możesz założyć, że ponieważ w kodzie nie ma żadnych odnośników (poza tymi
count
, które możesz bezpiecznie zignorować), nie może on przeciekać. Jednak finalizator tworzy dwie nowe Hydry i chociaż nie ma w nich również odniesień, będą się zatrzymywać do czasu sfinalizowania. Oznacza to, że program wycieka pamięć tylko podczas odśmiecania pamięci - stąd wywołania doSystem.gc()
iSystem.runFinalization()
.źródło
System.gc()
iSystem.runFinalization()
konieczne? To znaczy, czy gc czasami uruchamia się losowo, czy trzeba albo wypełnić trochę pamięci, albo wywołać gc?System.gc()
iSystem.runFinalization()
nie byłoby konieczne. Usuwanie śmieci odbywałoby się naturalnie z powodu presji pamięci. Jednak w tej aplikacji nie ma presji pamięci, dopóki nie rozpocznie się czyszczenie pamięci. Myślałem o sztucznym wprowadzeniu niektórych (na przykład poprzez poruszanie sięnew Hydra()
w pętli), ale pomyślałem, że to było bardziej złe.do
Używając języka programowania C i testowanego z jądrem Linux 2.6.32-49-generic i libc-2.11.1.so.
Osiąga się to poprzez blokowanie wszelkich sygnałów oprócz SIGKILL i SIGSTOP.
To mnie faktycznie pomyliło ... Zarówno zabicie, jak i zamknięcie obu powoduje zakończenie procesu, pozwalając systemowi operacyjnemu odzyskać pamięć przydzieloną przez proces. Ale potem pomyślałem, że zamykając go, możesz chcieć zamknąć terminal lub inny proces nadrzędny, który wykonuje proces wycieku pamięci. Jeśli dobrze to zrozumiałem, rozwiązałem ten problem, blokując wszelkie sygnały, które zamieniają proces w demona po zakończeniu procesu nadrzędnego. W ten sposób możesz zamknąć terminal, w którym działa proces, który będzie kontynuował działanie i przejdzie do wycieku pamięci.
Proces nie rozwidla się.
Nie pojawiają się nowe wątki.
Nie pojawiają się nowe procesy.
Tyle, ile może zapewnić system operacyjny.
Dodano komentarze do źródła.
I w końcu oto kod:
Dla każdego, kto jest zainteresowany tym, co się stanie, jeśli ten program będzie nadal działał: Na moim systemie testowym z 2 GB pamięci RAM i 4 GB miejsca wymiany zajęło około 10 minut, aby wypełnić pamięć RAM i wymienić. Zabójca OOM rozpoczął pracę, a trzy minuty później wszystkie procesy zostały zabite. System upuścił nawet mysz, klawiaturę i wyświetlacz. /var/log/kern.log nie pokazuje żadnych użytecznych informacji, z wyjątkiem procesów, które zostały zabite.
źródło
Pure Bash
Nie widelec-bomba, obiecuję:
Wygląda bardzo podobnie do bomby widelcowej i wykorzystuje podobną technikę rekurencyjną, ale bez widelców. Oczywiście spowoduje to wyczerpanie powłoki z pamięci, dlatego zaleca się uruchomienie nowej powłoki przed wklejeniem tego polecenia.
:
$@
podwójną (lista arg):
funkcji wywoływana jest z początkowym arg:
Wynik:
W poprzedniej edycji tej odpowiedzi zrobiłem to
a=$(yes)
, ale zauważyłem zasadę „Program nie może uruchamiać innego programu”, więcbash
zamiast tego muszę używać czystego, bez wywoływania coreutils lub czegokolwiek innego.Oto kolejny:
PROSZĘ NIE URUCHAMIAĆ TEGO NA MASZYNIE PRODUKCYJNEJ
Ponownie, to nie jest bomba widelca - wszystko jest uruchamiane z jednego wątku. Wydaje się, że całkiem nieźle sprowadza moją maszynę wirtualną Ubuntu na kolana, pozostawiając niewiele miejsca na odzyskanie, poza restartem.
Podobnie jak w przypadku klasycznej bomby widełkowej,
:()
zdefiniowano funkcję rekurencyjną . Jednak nie rozdziela połączeń do siebie. Zamiast tego wywołuje się z jednym argumentem, który sam jest wywoływany w procesie podstawiania . Ponieważ podstawianie procesów działa poprzez otwarcie deskryptora pliku/dev/fd/n
, to nie tylko zjada pamięć procesu (bash), ale także zużyje trochę pamięci jądra. Na moim komputerze Ubuntu powoduje to, że menedżer okien przestaje działać po kilku sekundach, a następnie wkrótce po wyświetleniu tego ekranu:Kliknięcie
OK
powoduje wyświetlenie tego ekranu:Żadna z tych opcji nie wydaje się zbyt pomocna - w tym momencie ponowne uruchomienie wydaje się jedyną dobrą opcją.
źródło
$ which yes
->/usr/bin/yes
XML
Następnie przekaż dokument do analizatora składni XML, który nie wykrywa pętli / rekurencji odniesień do encji. Na przykład
xpath
dołączony do perla:Jak to działa:
<boom a="&a;">
"&a;"
do"&b;&b;"
"&b;"
wbudowany we"&c;&c;"
(na powrót, że rozszerzenie drugiej"&b;"
)"&c;"
etc ...Gdyby nastąpiło pełne rozwinięcie, nastąpiłoby rozwinięcie 2 ^ 52 „ka-boom!”. Zakładając 2 bajty na znak, spróbuje użyć 64 PiB. Rozszerzenie brzmi „ka-boom!” na raz, więc zwykle możesz zobaczyć, jak zużywa całą pamięć u góry.
To pod różnymi nazwami, dobry przegląd tutaj: http://projects.webappsec.org/w/page/13247002/XML%20Entity%20Expansion
źródło
C ++
Ten kod był nieoczekiwany! Zawiesił mój komputer, gdy menedżer zadań był otwarty i pokazał, że zabrał 890 Mb pamięci w ciągu 1 sekundy, a następnie zawiesił się. Nie wiem, jak to działa, może ciągle przekazuje pamięć do zmiennej. Aby zbadać więcej tego kodu, dodałem instrukcję
delete a;
i wszystko było w porządku podczas testowania (bez zawieszania się) Więc myślę, że fragment pamięci jest podane (z powodunew int
), a następnie cofnięte (z powodudelete a
) do wolnego miejsca w nowym kodzie poniżej.Stwierdzam więc, że ŻADNA RAMKA W TYM ŚWIECIE NIE MOŻE OBEJMOWAĆ TEGO KODU !!!
EDYCJA : Ale wiele procesorów może np.
intel core 2 duo
Nie obsługiwać tego kodu, aleintel core i-series
może (działało dla mnie ...)Pamiętaj, że odpowiedź na pytanie to pierwszy kod, drugi służy wyjaśnieniu.
źródło
new int
nawet jeśli nadpisałeś wskaźnik, więc nigdy nie będziesz mógł uzyskać do niego dostępu ponownie ... Więc nie jest wywoływane zbieranie śmieci i zapełniasz pamięć szybciej niż gruby dzieciak zjada kręgleBrainFuck
Wyjaśnienie:
Aby wejść do pętli, zwiększa komórkę do 1. Przesuwa się do następnej komórki, zwiększając ją do 1, o ile ostatnia komórka była dodatnia.
Zwykle interpreter BrainFuck ma wadę polegającą na twardym ograniczeniu liczby komórek na taśmie, ale niektóre interpretery dodają komórki dynamicznie. Będą one nadal zużywać pamięć, dopóki nie będzie więcej do zużywania.
beef
jest jednym z takich interpreterów i jest dostępny w Centrum Oprogramowania Ubuntu, a moje bieżące uruchamianie na nieużywanym komputerze rozpoczęło się 29 godzin temu i zużyło w tym czasie 1 GB pamięci RAM. Oto wynik działaniatop
Ma 4 GB pamięci podręcznej i 6 GB wymiany, więc chyba zaktualizuję tę odpowiedź o to, jak poszło za 12 dni.
AKTUALIZACJA 03.24 17:11
AKTUALIZACJA 03.31 00:20
To działa od 10 dni. Wygląda na to, że będzie działał jeszcze co najmniej 10, zanim wydarzy się coś interesującego.
źródło
C i POSIX
Tutaj dążę do wysoce przenośnego rozwiązania. Problem polega na tym, że czyste C nie wydaje się mieć sposobu, aby powiedzieć systemowi operacyjnemu, że pamięć powinna pozostać przydzielona po zamknięciu programu. Dlatego pozwalam sobie na korzystanie z POSIX; większość systemów operacyjnych ma pewne zastrzeżenia do zgodności z POSIX, w tym Windows, Linux i MacOS X. Jednak przetestowałem to tylko na Ubuntu 12.04 32bit. Nie wymaga uprawnień administratora.
To rozwiązanie jest zasadniczo
while(1){malloc(1);}
rozwiązaniem tradycyjnym . Jednak zamiast malloc korzysta z funkcji pamięci współdzielonej POSIX. Ponieważ przypisuje identyfikator pamięci współdzielonej do każdego przydziału, dostęp do pamięci jest nadal możliwy po zakończeniu procesu. Dlatego jądro nie może zwolnić pamięci.źródło
DO#
Zapomnienie o anulowaniu subskrypcji zdarzeń, zanim program obsługi wyjdzie poza zasięg spowoduje, że .NET wyciek pamięci, dopóki nie zgłosi wyjątku OutOfMemoryException.
Objaśnienie : Wewnątrz
while
pętli konstruujemy nowy obiekt, powodując, że struktura przydziela więcej pamięci, ale również zapobiegamyB
zwolnieniu nowej instancji , gdy wykracza ona poza zakres, poprzez przypisanie metody instancji do zdarzenia w innej klasie, w wyniku tego nowa instancjaB
nie jest dostępna dla naszego kodu, ale referencja nadal istnieje, co oznacza, że GC nie wyda go, dopókia
również nie wyjdzie poza zakres.Zdarzenia statyczne mają tę samą pułapkę, ponieważ nigdy nie wykraczają poza zakres, są czyszczone tylko po zakończeniu procesu, chyba że najpierw anulujesz subskrypcję zdarzenia. Zawsze przechowuj swoje referencje, ludzie!
Powyższe działa na tym samym pomyśle, program obsługi staje się nieosiągalny, gdy
while
pętla wykracza poza zakres, uniemożliwiając wypisanie się ze zdarzenia, co oznacza, że pamięć pozostanie tam, dopóki program się nie zakończy. Zdarzenia statyczne są prawdopodobnie bardziej niebezpieczne niż zdarzenia instancji, ponieważ możesz zagwarantować, że nigdy nie wykroczą poza zakres.EDYCJA : Możesz również zrobić to samo z praktycznie każdym innym obiektem, pod warunkiem, że dodasz referencję, jednocześnie zapewniając, że nie ma możliwości jej uwolnienia.
Oto przykład, który wykorzystuje obiekty statyczne i tablice.
Tablice są ciągle dodawane do listy, ale nie ma możliwości wyczyszczenia listy bez modyfikacji kodu, co byłoby niemożliwe w przypadku aplikacji o zamkniętym źródle. Zwiększenie liczby przekazywanych
Leak.Add
spowoduje szybsze wycieki, jeśli ustawisz go wystarczająco wysoko, spowoduje to natychmiastowe zgłoszenie wyjątku OverflowException.źródło
bash (bez zewnętrznych narzędzi)
Nie ma tu widelca.
Ostrzeżenie: może zabić twoją powłokę.
Po prostu próbuję utworzyć tablicę liczb całkowitych dla odniesienia, ponieważ ciągle zapominam, jak wyglądają liczby całkowite.
Prowadzi do:
źródło
J (7)
OSTRZEŻENIE: To zamroziło mój system, gdy go wypróbowałem (Windows 8, J 8.01, w terminalu qt).
2#
podwaja długość argumentu poprzez duplikowanie każdego elementu,^:_
znajduje punkt stały danej funkcji (ale nie ma takiej, więc zapętla się w nieskończoność),[_
nazywa to_
argumentem.źródło
Haskell (numer Grahama)
To bardzo proste: oblicza liczbę Grahama
W przeciwieństwie do innych przykładów, nie będzie działać wiecznie ... zużyje dużo procesora, ale teoretycznie może się skończyć. gdyby nie fakt, że do przechowywania numeru ...
(według wikipedii)
Chodzi więc o to, że pamięć będzie wykorzystywana przez (szereg coraz bardziej) ogromnych
Integer
rozmiarów (liczby całkowite Haskella mają dowolną wielkość).Jeśli chcesz to przetestować, być może będziesz musiał zwiększyć rozmiar stosu lub załadować go do środka
ghci
.źródło
Inspirowany przez @comintern.
Zastępowanie / dev / null. Włączanie trybu podstępnego. Wymaga nagłówków jądra, trybu superużytkownika i działającego kompilatora.
Baw się dobrze.
Makefile:
Kod źródłowy:
Ostrzeżenie może zmusić Cię do ponownego uruchomienia!
Aby go usunąć:
źródło
Rubin
Każdy zna tę sumę (1 / n ^ 2) = pi ^ 2/6
Mogę więc zdefiniować funkcję aproksymacji:
Oczywiście (1 .. nieskończoność) będzie działać dziko.
Zauważ jednak, że użycie leniwego sprawiłoby, że to zadziała;)
źródło
C -
2825 znaków (pełny program)Nie uruchamiaj tego, w przeciwnym razie twój system szybko się zamrozi!
Wezwanie do malloc zarezerwuje 9 bajtów pamięci i będzie regularnie żądać nowych stron pamięci w systemie operacyjnym. Pamięć przydzielona przez malloc jest natychmiast wyciekana, ponieważ nie jest przechowywany wskaźnik do zwróconego adresu. Gdy w systemie zabraknie pamięci (pamięci RAM i przestrzeni wymiany) lub zostanie osiągnięty limit pamięci dla procesu, program wyrwie się z pętli while i zakończy działanie.
źródło
main(){while(malloc(9));}
zapisuje kolejne 3 znaki i prawie natychmiast wypełnia moją pamięć.VBScript
Tworzymy słownik, który wskazuje na siebie. Myślimy, że zniszczymy słownik, ustawiając go na Nic. Jednak słownik nadal istnieje w pamięci, ponieważ ma prawidłowe (okrągłe) odwołanie.
Pętla, ale także wieprz pamięci, powoduje zawieszenie się programu. Po zamknięciu programu pamięć jest nadal używana. System można przywrócić tylko poprzez jego ponowne uruchomienie.
źródło
Tak i tmpfs
Po co pisać nowy program, jeśli jest dostępny bezpłatnie z Ubuntu?
Jak zapewne wiesz, lub już zgadłeś, Ubuntu domyślnie montuje / run / user / jako tmpfs, który jest rodzajem dysku RAM .
Nie musisz go nawet zamykać. Grzecznie się zamknie, pozostawiając sporo przydzielonej pamięci. Przypuszczam, że
yes
jest to jednowątkowy, jednoprocesowy program, który nie wywołuje żadnego innego (zapis na istniejącym dysku RAM jest również trywialnie przenośny na wybrany przez ciebie język).Ma niewielki błąd: Ubuntu domyślnie ogranicza zapisywalne przez użytkownika tmpfs / run / 1000 do 100 MB, więc funkcja zamiany śmierci może nie być obsługiwana na twoim komputerze po wyjęciu z pudełka. Udało mi się to jednak naprawić na moim komputerze za pomocą następującego szybkiego obejścia:
źródło
/run/user
katalogu. Z jakiej wersji Ubuntu korzystasz i co zainstalowałeś?tmpfs
zamontowane jakieś systemy plików, możesz je wymienićdf -t tmpfs
. Mój system Ubuntu ma piękny duży/run/shm
dostępny ...Grzmotnąć
Ostrzeżenie: Poniższy kod uniemożliwi uruchomienie komputera.
Ostrzeżenie: powyższy kod uniemożliwi uruchomienie komputera.
Zamień / dev / sda na dysk rozruchowy. To zapisuje E8 FD FF na początku sektora rozruchowego. Podczas uruchamiania BIOS odczytuje sektor rozruchowy do pamięci i wykonuje go. Te kody są równoważne z tym zestawem:
Jest to nieskończona rekurencja, która ostatecznie spowoduje przepełnienie stosu.
źródło
jmp
zamiastcall
Haskell
To próbuje zsumować liczby zliczające. Haskell oblicza sumy częściowe, staje się po prostu nieskończoną instrukcją dodawania. Jeśli uruchomisz kompilator z flagami optymalizacji, może on jednak nie działać.
źródło
Grzmotnąć
Ponieważ możemy używać narzędzi, które nie są specjalnie zaprojektowane aby zużywać pamięć, skupię się na narzędzie do wolnej pamięci:
swapon
. Służy to do zwolnienia pamięci przez jądro poprzez zapis na dysk.Ten skrypt wykonuje dwie optymalizacje: (1) Montowanie tmp jako tmpfs (rodzaj dysku RAM) w celu przyspieszenia / tmp i (2) tworzenie pliku wymiany w celu zwolnienia pamięci. Każdy z nich jest sam w sobie uzasadniony, ale jeśli nieostrożny użytkownik zrobi oba, wówczas rozpoczyna cykl wymiany: gdy system operacyjny próbuje zamienić strony, zapisuje je w tmpfs; powoduje to, że tmpfs zużywają więcej pamięci; zwiększa to presję pamięci, powodując zamianę większej liczby stron. Może to potrwać kilka minut na mojej maszynie wirtualnej, dużo czasu, abyś zobaczył, jak system kopie się w dziurę za pomocą
top
.Zamknięcie programu nie ma większego znaczenia, ponieważ sam program prawie nie przydziela żadnej pamięci. Rzeczywiście,
swapoff
zwalnianie pamięci nie jest trywialne, ponieważ nie można zwolnić pamięci przez odmontowanie tmpfs przed plikiem wymiany, a jest to trudne do momentu zwolnienia pamięci.Ta odpowiedź może być uważana za przestrogę przed oślepianiem, stosując fajne sztuczki z sieci bez ich zrozumienia.
źródło
Perl
Wykorzystuje odwołania cykliczne. Liczba referencji dla zmiennych nigdy nie osiągnie 0, a referencje nigdy nie zostaną wyrzucone do pamięci.
Być może będziesz musiał uzbroić się w cierpliwość, ale z pewnością udusisz system. Dysk zacznie wirować szybciej, a opary mogą być widoczne.
źródło
PHP (tylko Linux):
Ten kod nie został przetestowany, ponieważ nie mam komputera z systemem Linux z uruchomionym php.
Ale to jest mój dowód koncepcji:
To zapełni pamięć ogromnymi obrazami RGBA (10000 x 10000 pikseli).
Jedynym sposobem na wyłączenie tego dziecka jest wyłączenie zasilania.
Cały kod jest komentowany.
Wszelkie ulepszenia, wątpliwości, błędy lub cokolwiek innego, użyj pola komentarza poniżej.
źródło
Python - 56
Tworzy klasę, definiuje metodę ustawiania atrybutów, ustawia w niej atrybut i tworzy instancję początkową, którą następnie próbuje ustawić atrybut.
Prosta funkcja rekurencyjna (
def f(x):f(x)
) wydawała się trochę niewyobrażalna, więc postanowiłem nigdy nie wywoływać funkcji.Zarządzanie pamięcią może uchwycić głębokość rekurencji, ale tak naprawdę zależy to od implementacji.
Jeśli to bomba wideł, proszę mi powiedzieć.
źródło
RuntimeError: maximum recursion depth exceeded while calling a Python object
. Nawet ustawienie maksymalnego limitu rekurencjisys.setrecursionlimit
prawie bez pamięci jest używane, zanim ulegnie awarii z powodu błędu segmentacji.Perl
To proste, ale miałem ochotę zagrać w golfa.
Po dwóch iteracjach
$x
zawiera odwołanie do tablicy zawierającej odwołanie do tablicy zawierającejundef
.Zużycie pamięci jest liniowe w czasie, z małymi przydziałami, ale zajęło mi to tylko kilka sekund, aby znacznie spowolnić menedżera okien w systemie Ubuntu Linux. Pół minuty później zajął się tym zabójca OOM.
źródło
ECMAScript 6:
Nie golfowany:
Uwaga: używa
setTimeout
, który jest zdefiniowany jako część Timerów - HTML Living Standard .Wypróbuj w przeglądarce Mozilla Firefox (możesz wkleić go w konsoli programisty). Firefox zużywa coraz więcej pamięci i wykorzystuje
100%
procesor na maszynie jednordzeniowej (na maszynie 4-rdzeniowej, takiej jak moja, używa25%
procesora). Ma także tę dodatkową zaletę, że nie można go zatrzymać; jeśli możesz otworzyć menedżera zadań, możesz zabić Firefoksa za jego pomocą.źródło
Grzmotnąć
Utwórz pusty plik
test
Zastąp
/dev/null/
ten plik tekstowy$ sudo mv test /dev/null
Działa to w podobny sposób jak odpowiedź @ Comintern. Wszystkie dane wyjściowe
/dev/null
zostaną teraz dołączone do tego pliku tekstowego, który z czasem stanie się ogromny i spowoduje awarię systemu.źródło
/dev
jest adevtmpfs
, może to zapełnić i utrudnić działanie systemu. Zgaduję, że taka jest intencja tej odpowiedzi.Bash: 7 znaków
To powinno być najprostsze rozwiązanie bash. Bez widelców, bez oszukiwania.
Zaleca się, aby nie uruchamiać tego jako root.
źródło
unset
zmienną, pamięć pozostanie przydzielona do momentu zabicia powłoki. Możesz obejrzeć rzeźtop
.unset x
pamięć. pdksh również zwalnia pamięć, ale ksh93 nie zwalnia jej,exit
aw ksh93 zrzuca rdzeń.yes
zabicia, w którym to momencie pozostaje tam,unset
nie wywołując żadnego efektu. Ale dzieje się tak w dużym systemie pamięci, a posiadanie zmiennej, która ma kilka gigabajtów, nie sprawia problemów (dopóki nie zdecyduje się zabić powłoki).do
Cóż, zajmuje pamięć strona po stronie i wreszcie nie ma już pamięci.
źródło
Rubin
Po prostu bez końca dołącza (rekurencyjne!) Odniesienia do siebie.
Dowiedziałem się o tym małym klejnocie, gdy ktoś złamał moją piaskownicę Ruby . :RE
Demonstracja jego rekurencyjnych aspektów:
źródło
C ++ 79
Nie golfa
Poprawiłem wpis, aby zawierał połączenie z głównego.
źródło