Capturando java.lang.OutOfMemoryError?


101

A documentação para java.lang.Errordiz:

Um erro é uma subclasse de Throwable que indica problemas sérios que um aplicativo razoável não deve tentar detectar

Mas como java.lang.Erroré uma subclasse de java.lang.Throwable, posso pegar esse tipo de Throwable.

Eu entendo por que não é uma boa ideia capturar esse tipo de exceção. Pelo que entendi, se decidirmos capturá-lo, o manipulador de captura não deve alocar nenhuma memória por si mesmo. Caso contrário OutOfMemoryError, será lançado novamente.

Então, minha pergunta é:

  1. Existem cenários do mundo real em que pegar java.lang.OutOfMemoryErrorpode ser uma boa ideia?
  2. Se decidirmos capturar java.lang.OutOfMemoryError, como podemos ter certeza de que o manipulador de captura não aloca nenhuma memória por si mesmo (nenhuma ferramenta ou prática recomendada)?


Para sua primeira pergunta, acrescentarei que capturarei o OutOfMemoryError para (pelo menos tentar) notificar o usuário sobre o problema. Anteriormente, o erro não era detectado pela cláusula catch (Exception e) e nenhum feedback era mostrado ao usuário.
Josep Rodríguez López

1
Existem casos específicos, por exemplo, alocação de uma matriz gigantesca, onde se pode detectar o erro OOM em torno dessa operação e se recuperar razoavelmente bem. Mas colocar o try / catch em torno de um grande blob de código e tentar se recuperar de forma limpa e continuar é provavelmente uma má ideia.
Hot Licks de

Respostas:


85

Eu concordo e discordo da maioria das respostas aqui.

Há uma série de cenários em que você pode querer pegar um OutOfMemoryErrore, na minha experiência (em JVMs do Windows e Solaris), raramente éOutOfMemoryError a sentença de morte para um JVM.

Há apenas um bom motivo para detectar um: OutOfMemoryErrorfechar normalmente, liberando recursos de maneira limpa e registrando o motivo da falha da melhor maneira possível (se ainda for possível).

Em geral, isso OutOfMemoryErrorocorre devido a uma alocação de memória em bloco que não pode ser satisfeita com os recursos restantes do heap.

Quando o Erroré lançado, o heap contém a mesma quantidade de objetos alocados que antes da alocação malsucedida e agora é a hora de descartar as referências a objetos de tempo de execução para liberar ainda mais memória que pode ser necessária para limpeza. Nesses casos, pode até ser possível continuar, mas isso seria definitivamente uma má ideia, pois você nunca pode ter 100% de certeza de que a JVM está em um estado reparável.

Demonstração que OutOfMemoryErrornão significa que a JVM está sem memória no bloco catch:

private static final int MEGABYTE = (1024*1024);
public static void runOutOfMemory() {
    MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
    for (int i=1; i <= 100; i++) {
        try {
            byte[] bytes = new byte[MEGABYTE*500];
        } catch (Exception e) {
            e.printStackTrace();
        } catch (OutOfMemoryError e) {
            MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
            long maxMemory = heapUsage.getMax() / MEGABYTE;
            long usedMemory = heapUsage.getUsed() / MEGABYTE;
            System.out.println(i+ " : Memory Use :" + usedMemory + "M/" + maxMemory + "M");
        }
    }
}

Saída deste código:

1 : Memory Use :0M/247M
..
..
..
98 : Memory Use :0M/247M
99 : Memory Use :0M/247M
100 : Memory Use :0M/247M

Se estiver executando algo crítico, geralmente pego o Error, registro no syserr e, em seguida, registro usando minha estrutura de registro de escolha, e prossigo para liberar recursos e encerrar de forma limpa. Qual o pior que pode acontecer? A JVM está morrendo (ou já está morta) de qualquer maneira e, ao detectar o, Errorhá pelo menos uma chance de limpeza.

A ressalva é que você deve visar a detecção desses tipos de erros apenas em lugares onde a limpeza é possível. Não cubra tudo catch(Throwable t) {}ou um absurdo como esse.


Concordo, vou postar meu experimento em uma nova resposta.
Senhor Smith,

4
"você nunca pode ter 100% de certeza de que a JVM está em um estado reparável": porque o OutOfMemoryErrorpode ter sido acionado de um ponto que colocou seu programa em um estado inconsistente, porque ele pode ser acionado a qualquer momento. Consulte stackoverflow.com/questions/8728866/…
Raedwald

No OpenJdk1.7.0_40, não recebo nenhum erro ou exceção quando executo este código. Até eu mudei o MEGABYTE para GIGABYTE (1024 * 1024 * 1024). É porque o otimizador remove a variável 'byte [] bytes', uma vez que não é usada no resto do código?
RoboAlex

"Existem vários cenários em que você pode desejar capturar um OutOfMemoryError" versus "Há apenas uma boa razão para capturar um OutOfMemoryError" . Se decidir!!!
Stephen C

3
Cenário do mundo real quando você PODE querer capturar o erro OutOfMemory: quando ele é causado ao tentar alocar um array com mais de 2G elementos. O nome do erro é um pouco incorreto neste caso, mas ainda é um OOM.
Charles Roth

31

Você pode se recuperar dele:

package com.stackoverflow.q2679330;

public class Test {

    public static void main(String... args) {
        int size = Integer.MAX_VALUE;
        int factor = 10;

        while (true) {
            try {
                System.out.println("Trying to allocate " + size + " bytes");
                byte[] bytes = new byte[size];
                System.out.println("Succeed!");
                break;
            } catch (OutOfMemoryError e) {
                System.out.println("OOME .. Trying again with 10x less");
                size /= factor;
            }
        }
    }

}

Mas isso faz sentido? O que mais você gostaria de fazer? Por que você inicialmente alocaria tanta memória? Menos memória também está OK? Por que você ainda não faz uso dele? Ou, se isso não for possível, por que não apenas dar mais memória à JVM desde o início?

De volta às suas perguntas:

1: existe algum cenário de palavra real ao capturar java.lang.OutOfMemoryError pode ser uma boa ideia?

Nenhum vem à mente.

2: se capturarmos java.lang.OutOfMemoryError, como podemos ter certeza de que o manipulador de captura não aloca nenhuma memória por si mesmo (nenhuma ferramenta ou prática recomendada)?

Depende do que causou o OOME. Se for declarado fora do trybloco e acontecer passo a passo, então suas chances são pequenas. Você pode querer reservar algum espaço de memória com antecedência:

private static byte[] reserve = new byte[1024 * 1024]; // Reserves 1MB.

e, em seguida, defina-o para zero durante OOME:

} catch (OutOfMemoryException e) {
     reserve = new byte[0];
     // Ha! 1MB free!
}

É claro que isso não faz sentido;) Basta fornecer à JVM memória suficiente conforme sua aplicação requer. Execute um profiler, se necessário.


1
Mesmo reservando espaço, não há garantia de uma solução de trabalho. Esse espaço pode ser ocupado por algum outro tópico também;)
Wolph

@Wolph: Então dê mais memória à JVM! O_o Com tudo, de fato não faz sentido;)
BalusC

2
O primeiro fragmento funciona porque o objeto que disparou o erro é um único objeto BIG (a matriz). Quando a cláusula catch é atingida, ela foi coletada pela JVM com fome de memória. Se você estava usando o mesmo objeto fora do bloco try, ou em outro encadeamento, ou no mesmo catch, a JVM não o coleta, tornando impossível criar um novo objeto único de qualquer tipo. o segundo snippet, por exemplo, pode não funcionar.
Senhor Smith,

3
por que não simplesmente defini-lo como null?
Pacerier

1
@MisterSmith Seu comentário não faz sentido. O grande objeto não existe. Ele não foi alocado em primeiro lugar: ele acionou o OOM, então certamente não precisa de GC.
Marquês de Lorne

16

Em geral, é uma má ideia tentar capturar e se recuperar de um OOM.

  1. Um OOME também pode ter sido lançado em outros threads, incluindo threads que seu aplicativo nem conhece. Qualquer um desses threads agora estará morto e qualquer coisa que estava esperando por uma notificação pode ficar paralisada para sempre. Resumindo, seu aplicativo pode estar com problemas terminais.

  2. Mesmo se a recuperação for bem-sucedida, sua JVM ainda pode estar sofrendo de falta de heap e seu aplicativo terá um desempenho péssimo como resultado.

A melhor coisa a fazer com um OOME é deixar o JVM morrer.

(Isso pressupõe que a JVM faz morrer. Por exemplo Ooms em um fio de servlet Tomcat não matar o JVM, e isso leva ao Tomcat entrar em um estado catatônico, onde ele não vai responder a todos os pedidos ... nem mesmo pede para reiniciar.)

EDITAR

Não estou dizendo que é uma má ideia pegar OOM. Os problemas surgem quando você tenta se recuperar do OOME, deliberadamente ou por descuido. Sempre que você capturar um OOM (diretamente ou como um subtipo de Erro ou Throwable), deverá lançá-lo novamente ou providenciar para que o aplicativo / JVM seja encerrado.

À parte: isso sugere que, para obter o máximo de robustez em face de OOMs, um aplicativo deve usar Thread.setDefaultUncaughtExceptionHandler () para definir um manipulador que fará com que o aplicativo saia no caso de um OOME, não importa em qual thread o OOME é lançado. Eu estaria interessado em opiniões sobre isso ...

O único outro cenário é quando você tem certeza de que o OOM não resultou em nenhum dano colateral; ou seja, você sabe:

  • o que causou especificamente o OOME,
  • o que o aplicativo estava fazendo no momento, e que não há problema em simplesmente descartar esse cálculo e
  • que um OOME (aproximadamente) simultâneo não pode ter ocorrido em outro encadeamento.

Existem aplicativos onde é possível saber essas coisas, mas para a maioria dos aplicativos você não pode saber com certeza se a continuação após um OOME é segura. Mesmo que empiricamente "funcione" quando você tenta.

(O problema é que é necessária uma prova formal para mostrar que as consequências de OOMEs "antecipados" são seguras e que OOMEs "imprevistos" não podem ocorrer sob o controle de um OOME de try / catch.)


Sim, eu concordo com você. Em geral, é má ideia. Mas por que então tenho possibilidade de pegá-lo? :)
Denis Bazhenov

@dotsid - 1) porque há casos em que você deve capturá-lo e 2) porque tornar impossível capturar OOM teria um impacto negativo na linguagem e / ou em outras partes do Java runtime.
Stephen C

1
Você diz: "porque há casos em que você deve pegar". Então, essa foi parte da minha pergunta original. Quais são os casos em que você deseja capturar OOME?
Denis Bazhenov,

1
@dotsid - veja minha resposta editada. O único caso em que consigo pensar para capturar OOM é quando você precisa fazer isso para forçar um aplicativo multi-thread a sair no caso de um OOM. Talvez você queira fazer isso para todos os subtipos de Error.
Stephen C

1
Não é apenas uma questão de pegar OOMEs. Você também precisa se recuperar deles. Como um encadeamento se recupera se deveria (digamos) notificar outro encadeamento ... mas obteve um OOME? Claro, o JVM não morrerá. Mas é provável que o aplicativo pare de funcionar por causa de threads presos à espera de notificações de threads que foram reiniciados devido à captura de um OOME.
Stephen C

14

Sim, existem cenários do mundo real. Aqui está o meu: eu preciso processar conjuntos de dados de muitos itens em um cluster com memória limitada por nó. Uma determinada instância de JVM passa por muitos itens, um após o outro, mas alguns dos itens são muito grandes para processar no cluster: posso pegar o OutOfMemoryErrore anotar quais itens são muito grandes. Posteriormente, posso executar novamente apenas os itens grandes em um computador com mais RAM.

(Como é uma única alocação de vários gigabytes de uma matriz que falha, a JVM ainda está bem após detectar o erro e há memória suficiente para processar os outros itens.)


Então você tem código como byte[] bytes = new byte[length]? Por que não verificar sizeem um ponto anterior?
Raedwald

1
Porque o mesmo sizevai ficar bem com mais memória. Eu passo pela exceção porque na maioria dos casos tudo vai ficar bem.
Michael Kuhn

10

Definitivamente, existem cenários em que capturar um OOME faz sentido. O IDEA os pega e abre uma caixa de diálogo para permitir que você altere as configurações de memória de inicialização (e sai quando terminar). Um servidor de aplicativos pode capturá-los e relatá-los. A chave para fazer isso é fazer isso em um alto nível no despacho para que você tenha uma chance razoável de ter um monte de recursos liberados no ponto em que está capturando a exceção.

Além do cenário IDEA acima, em geral a captura deve ser de Throwable, não apenas OOM especificamente, e deve ser feita em um contexto onde pelo menos o thread será encerrado em breve.

É claro que na maioria das vezes a memória passa fome e a situação não pode ser recuperada, mas existem maneiras de fazer sentido.


8

Eu me deparei com essa pergunta porque estava me perguntando se seria uma boa ideia capturar OutOfMemoryError no meu caso. Estou respondendo aqui parcialmente para mostrar outro exemplo em que detectar este erro pode fazer sentido para alguém (ou seja, eu) e parcialmente para descobrir se é uma boa ideia no meu caso (sendo eu um desenvolvedor super júnior, nunca poderei tenha certeza sobre qualquer linha de código que eu escrever).

De qualquer forma, estou trabalhando em um aplicativo Android que pode ser executado em diferentes dispositivos com diferentes tamanhos de memória. A parte perigosa é decodificar um bitmap de um arquivo e desdobrá-lo em uma instância de ImageView. Não quero restringir os dispositivos mais poderosos em termos de tamanho de bitmap decodificado, nem posso ter certeza de que o aplicativo não será executado em algum dispositivo antigo que nunca vi com memória muito baixa. Portanto, eu faço o seguinte:

BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); 
bitmapOptions.inSampleSize = 1;
boolean imageSet = false;
while (!imageSet) {
  try {
    image = BitmapFactory.decodeFile(filePath, bitmapOptions);
    imageView.setImageBitmap(image); 
    imageSet = true;
  }
  catch (OutOfMemoryError e) {
    bitmapOptions.inSampleSize *= 2;
  }
}

Dessa forma, consigo prover dispositivos cada vez menos potentes de acordo com as necessidades e expectativas de seus usuários.


1
Outra opção seria calcular o tamanho dos bitmaps que você pode manipular em vez de tentar e falhar. “As exceções devem ser usadas para casos excepcionais” - acho que alguém disse. Mas direi que sua solução parece a saída mais fácil, talvez não a melhor, mas provavelmente a mais fácil.
jontejj

Depende do codec. Imagine que um bmp de 10 MB provavelmente resulte em apenas um pouco mais do que 10 MB de heap, enquanto um JPEG de 10 MB "explodirá". Mesmo no meu caso, em que desejo analisar um XML que pode variar enormemente dependendo da complexidade do conteúdo
Daniel Alder

5

Sim, a verdadeira questão é "o que você vai fazer no manipulador de exceções?" Para quase tudo que for útil, você alocará mais memória. Se você gostaria de fazer algum trabalho de diagnóstico quando ocorre um OutOfMemoryError, você pode usar o -XX:OnOutOfMemoryError=<cmd>gancho fornecido pelo HotSpot VM. Ele executará seu (s) comando (s) quando ocorrer um OutOfMemoryError e você poderá fazer algo útil fora do heap do Java. Em primeiro lugar, você realmente deseja evitar que o aplicativo fique sem memória, portanto, descobrir por que isso acontece é a primeira etapa. Em seguida, você pode aumentar o tamanho de heap do MaxPermSize conforme apropriado. Aqui estão alguns outros ganchos de HotSpot úteis:

-XX:+PrintCommandLineFlags
-XX:+PrintConcurrentLocks
-XX:+PrintClassHistogram

Veja a lista completa aqui


É ainda pior do que você pensa. Como um OutOfMemeoryError pode ser lançado em qualquer ponto de seu programa (não apenas a partir de uma newinstrução), seu programa estará em um estado indefinido quando você pegar a excção.
Raedwald de

5

Tenho um aplicativo que precisa se recuperar de falhas OutOfMemoryError e, em programas de thread único, sempre funciona, mas às vezes não funciona em programas de multi-thread. O aplicativo é uma ferramenta de teste Java automatizada que executa sequências de teste geradas com a profundidade máxima possível nas classes de teste. Agora, a IU deve ser estável, mas o mecanismo de teste pode ficar sem memória enquanto aumenta a árvore de casos de teste. Eu lido com isso pelo seguinte tipo de idioma de código no mecanismo de teste:

boolean isOutOfMemory = false; // sinalizador usado para relatórios
experimentar {
   SomeType largeVar;
   // Loop principal que aloca mais e mais para largeVar
   // pode terminar OK, ou aumentar OutOfMemoryError
}
catch (OutOfMemoryError ex) {
   // largeVar agora está fora do escopo, então o lixo está
   System.gc (); // limpar dados largeVar
   isOutOfMemory = true; // sinalizador disponível para uso
}
// programa teste sinalizador para relatar recuperação

Isso sempre funciona em aplicativos de thread único. Mas recentemente coloquei meu mecanismo de teste em um thread de trabalho separado da IU. Agora, a falta de memória pode ocorrer arbitrariamente em qualquer segmento e não está claro para mim como capturá-la.

Por exemplo, fiz o OOME ocorrer enquanto os quadros de um GIF animado em minha IU estavam sendo alternados por um thread proprietário criado nos bastidores por uma classe Swing que está fora do meu controle. Eu pensei que tinha alocado todos os recursos necessários com antecedência, mas claramente o animador está alocando memória toda vez que busca a próxima imagem. Se alguém tiver uma ideia sobre como lidar com OOMEs levantados em qualquer tópico, eu adoraria ouvir.


Em um único aplicativo threaded, se você não estiver mais usando alguns dos novos objetos problemáticos cuja criação gerou o erro, eles podem ser coletados na cláusula catch. No entanto, se a JVM detectar que o objeto pode ser usado posteriormente, ele não pode ser coletado e o aplicativo explode. Veja minha resposta neste tópico.
Senhor Smith,

4

OOME pode ser capturado, mas geralmente será inútil, dependendo se a JVM é capaz de coletar como lixo alguns objetos quando a captura é alcançada e de quanta memória de heap resta nesse momento.

Exemplo: na minha JVM, este programa é executado até a conclusão:

import java.util.LinkedList;
import java.util.List;

public class OOMErrorTest {             
    public static void main(String[] args) {
        List<Long> ll = new LinkedList<Long>();

        try {
            long l = 0;
            while(true){
                ll.add(new Long(l++));
            }
        } catch(OutOfMemoryError oome){         
            System.out.println("Error catched!!");
        }
        System.out.println("Test finished");
    }  
}

No entanto, apenas adicionar uma única linha na captura mostrará do que estou falando:

import java.util.LinkedList;
import java.util.List;

public class OOMErrorTest {             
    public static void main(String[] args) {
        List<Long> ll = new LinkedList<Long>();

        try {
            long l = 0;
            while(true){
                ll.add(new Long(l++));
            }
        } catch(OutOfMemoryError oome){         
            System.out.println("Error catched!!");
            System.out.println("size:" +ll.size());
        }
        System.out.println("Test finished");
    }
}

O primeiro programa funciona bem porque quando o catch é atingido, a JVM detecta que a lista não será mais usada (esta detecção também pode ser uma otimização feita em tempo de compilação). Portanto, quando alcançamos a instrução print, a memória heap foi liberada quase totalmente, portanto, agora temos uma ampla margem de manobra para continuar. Este é o melhor caso.

No entanto, se o código for organizado como a lista llé usada após o OOME ter sido capturado, a JVM não será capaz de coletá-lo. Isso acontece no segundo trecho. O OOME, acionado por uma nova criação Longa, é capturado, mas logo estamos criando um novo Objeto (uma String na System.out,printlnlinha), e o heap está quase cheio, então um novo OOME é lançado. Este é o pior cenário: tentamos criar um novo objeto, falhamos, capturamos o OOME, sim, mas agora a primeira instrução que requer uma nova memória heap (por exemplo: criar um novo objeto) irá lançar um novo OOME. Pense nisso, o que mais podemos fazer neste momento com tão pouca memória sobrando ?. Provavelmente está saindo. Daí o inútil.

Entre os motivos da JVM não coletar recursos, um é realmente assustador: um recurso compartilhado com outras threads também fazendo uso dele. Qualquer pessoa com cérebro pode ver como é perigoso capturar OOME se inserido em algum aplicativo não experimental de qualquer tipo.

Estou usando uma JVM (JRE6) do Windows x86 de 32 bits. A memória padrão para cada aplicativo Java é 64 MB.


E se eu fizer ll=nulldentro do bloco de captura?
Naanavanalla

3

A única razão pela qual posso pensar em detectar erros OOM pode ser que você tenha algumas estruturas de dados massivas que não está mais usando e pode definir como null e liberar memória. Mas (1) isso significa que você está perdendo memória e deve corrigir seu código em vez de apenas mancar após um OOME, e (2) mesmo se você o detectasse, o que faria? OOM pode acontecer a qualquer momento, potencialmente deixando tudo pela metade.


3

Para a questão 2 já vejo a solução que sugeriria, da BalusC.

  1. Existe algum cenário de palavra real quando capturar java.lang.OutOfMemoryError pode ser uma boa ideia?

Acho que acabei de encontrar um bom exemplo. Quando o aplicativo awt está despachando mensagens, o OutOfMemoryError não bloqueado é exibido em stderr e o processamento da mensagem atual é interrompido. Mas o aplicativo continua funcionando! O usuário ainda pode emitir outros comandos sem saber dos problemas graves que acontecem nos bastidores. Principalmente quando ele não consegue ou não observa o erro padrão. Portanto, capturar a exceção oom e fornecer (ou pelo menos sugerir) a reinicialização do aplicativo é algo desejado.


3

Eu apenas tenho um cenário em que capturar um OutOfMemoryError parece fazer sentido e parece funcionar.

Cenário: em um aplicativo Android, desejo exibir vários bitmaps na resolução mais alta possível e quero poder ampliá-los com fluência.

Por causa do zoom fluente, quero ter os bitmaps na memória. No entanto, o Android tem limitações de memória que dependem do dispositivo e são difíceis de controlar.

Nessa situação, pode haver OutOfMemoryError ao ler o bitmap. Aqui, ajuda se eu pegar e continuar com uma resolução mais baixa.


0
  1. Depende de como você define "bom". Fazemos isso em nosso aplicativo da Web com erros e funciona na maioria das vezes (felizmente, agora OutOfMemorynão acontece devido a uma correção não relacionada). No entanto, mesmo se você pegá-lo, ele ainda pode ter quebrado algum código importante: se você tiver vários threads, a alocação de memória pode falhar em qualquer um deles. Portanto, dependendo do seu aplicativo, ainda há de 10 a 90% de chance de ele ser irreversivelmente quebrado.
  2. Pelo que eu entendo, o desdobramento pesado da pilha ao longo do caminho irá invalidar tantas referências e, assim, liberar tanta memória que você não deve se preocupar com isso.

EDIT: Eu sugiro que você experimente. Digamos, escreva um programa que chame recursivamente uma função que aloque progressivamente mais memória. Pegue OutOfMemoryErrore veja se você pode continuar a partir desse ponto de forma significativa. De acordo com minha experiência, você conseguirá, embora no meu caso tenha acontecido no servidor WebLogic, então pode ter havido alguma magia negra envolvida.


-1

Você pode capturar qualquer coisa em Throwable; de ​​modo geral, você só deve capturar subclasses de Exception, exceto RuntimeException (embora uma grande parte dos desenvolvedores também capture RuntimeException ... mas essa nunca foi a intenção dos designers de linguagem).

Se você pegasse OutOfMemoryError, o que diabos você faria? A VM está sem memória, basicamente tudo que você pode fazer é sair. Você provavelmente nem consegue abrir uma caixa de diálogo para dizer a eles que está sem memória, pois isso consumiria memória :-)

A VM lança um OutOfMemoryError quando está realmente sem memória (na verdade, todos os erros devem indicar situações irrecuperáveis) e não deve haver nada que você possa fazer para lidar com isso.

As coisas a fazer são descobrir por que você está ficando sem memória (use um criador de perfil, como o do NetBeans) e certifique-se de que não haja vazamentos de memória. Se você não tiver vazamentos de memória, aumente a memória que você aloca para a VM.


7
Um equívoco que sua postagem perpetua é que OOM indica que a JVM está sem memória. Em vez disso, na verdade indica que a JVM não pôde alocar toda a memória para a qual foi instruída. Ou seja, se a JVM tiver 10B de espaço e você 'renovar' um objeto 100B, ele falhará, mas você pode virar e 'renovar' um objeto 5B e ficar bem.
Tim Bender,

1
E se eu só precisava de 5B, por que estou pedindo 10B? Se você está fazendo a alocação com base em tentativa e erro, está fazendo errado.
TofuBeer

2
Acho que Tim quis dizer que você ainda pode executar algum trabalho mesmo com uma situação OutOfMemory. Pode haver memória suficiente para abrir uma caixa de diálogo, por exemplo.
Stephen Eilert
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.