Como você trava uma JVM?


144

Eu estava lendo um livro sobre habilidades de programação em que o autor pergunta ao entrevistado: "Como você colide com uma JVM?" Eu pensei que você poderia fazer isso escrevendo um loop for infinito que acabaria gastando toda a memória.

Alguém tem alguma ideia?



stackoverflow.com/questions/30072883/… "Se eu usar o JDK1.8_40 ou mais recente (Oracle ou OpenJDK fazem o mesmo), o código a seguir, juntamente com um redimensionamento de diálogo, trava o aplicativo (tentado JDK do Windows 7, x64, 64 bits)" - O código tem apenas 40 linhas e causa uma falha adequada da JVM.
Presidente da Dreamspace

Respostas:


6

A coisa mais próxima de uma única "resposta" é System.exit()que finaliza a JVM imediatamente sem limpeza adequada. Mas, além disso, código nativo e exaustão de recursos são as respostas mais prováveis. Como alternativa, você pode procurar no bug tracker da Sun por erros na sua versão da JVM, alguns dos quais permitem cenários de travamento repetíveis. Costumávamos ter falhas semi-regulares quando chegávamos ao limite de 4 Gb de memória nas versões de 32 bits (geralmente usamos 64 bits agora).


71
sem limpeza adequada? você tem certeza? A documentação diz "Encerra a máquina virtual Java atualmente em execução iniciando sua sequência de desligamento ... todos os ganchos de desligamento registrados, se houver, são iniciados ... todos os finalizadores não solicitados são executados" - essa não é a limpeza adequada?
user85421

51
Isso não está travando a JVM, está proposital e explicitamente iniciando um desligamento ordenado da execução.
BenM

9
Mais próximo de travar a jvm é Runtime.getRuntime (). Halt (status). De acordo com a documentação "esse método não faz com que os ganchos de desligamento sejam iniciados e não executa finalizadores não solicitados se a finalização na saída estiver ativada". Ainda não é um acidente, mas é mais próximo que o System.exit.
Henry

48
Esta é realmente uma resposta ruim.
Antonio

174

Eu não chamaria de lançar um OutOfMemoryError ou StackOverflowError uma falha. Essas são apenas exceções normais. Para travar realmente uma VM, existem três maneiras:

  1. Use JNI e falhe no código nativo.
  2. Se nenhum gerenciador de segurança estiver instalado, você poderá usar a reflexão para travar a VM. Isso é específico da VM, mas normalmente uma VM armazena vários ponteiros para recursos nativos em campos privados (por exemplo, um ponteiro para o objeto de thread nativo é armazenado em um campo longo em java.lang.Thread ). Basta alterá-los por meio de reflexão e a VM travará mais cedo ou mais tarde.
  3. Todas as VMs têm bugs, então você só precisa acionar uma.

Para o último método, tenho um pequeno exemplo, que trava uma VM silenciosa do Sun Hotspot:

public class Crash {
    public static void main(String[] args) {
        Object[] o = null;

        while (true) {
            o = new Object[] {o};
        }
    }
}

Isso leva a um estouro de pilha no GC, para que você não obtenha StackOverflowError, mas uma falha real, incluindo um arquivo hs_err *.


9
Uau! Isso trava o Sun Java 5, o Sun Java 6 e o ​​OpenJDK 6 (no Ubuntu 9.04) sem o arquivo hs_err *, mas apenas com a "Falha de segmentação!" ...
Joachim Sauer

1
System.exit () é uma maneira muito mais fácil de falhar uma JVM (a menos que um gerente de segurança está instalado)
instantsetsuna

4
Não sei quando foi corrigido, mas apenas testado em 1.7.0_09 e está bom. Apenas obtive o esperado: Exceção no encadeamento "main" java.lang.OutOfMemoryError: espaço de heap Java em CrashJVM.main (CrashJVM.java:7)
Chad NB

2
Tentei o código acima no Intel Core i7 de 2,4 GHz / 8 GB de RAM / JDK1.7 64 bits, mas a JVM ainda está ativa após 20 minutos. (Engraçado: o ventilador do meu laptop estava mais alto que um avião de caça no céu). Esse problema foi corrigido no JDK 1.7+?
realPK

3
No JDK 1.8_u71, isso causa umjava.lang.OutOfMemoryError: GC overhead limit exceeded
Clashsoft 24/01

124

JNI . De fato, com o JNI, travar é o modo padrão de operação. Você tem que trabalhar muito duro para não travar.


4
Talvez os designers da JNI tivessem ouvido falar sobre software apenas para falhas , mas não entenderam a idéia.
Tom Anderson

56

Usa isto:

import sun.misc.Unsafe;

public class Crash {
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    public static void crash() {
        unsafe.putAddress(0, 0);
    }
    public static void main(String[] args) {
        crash();
    }
}

Essa classe deve estar no caminho de classe de inicialização porque está usando código confiável, portanto, execute assim:

java -Xbootclasspath / p :. Batida


14
Em vez de usar -Xbootclasspath, você também pode fazer o seguinte: Field f = Unsafe.class.getDeclaredField( "theUnsafe" ); f.setAccessible( true ); unsafe = (Unsafe) f.get( null );Funcionou muito bem para mim.
insistente

Unsafeé, por definição, "inseguro". Isso é meio trapaceiro.
Hot Licks

1
Trabalho confirmado usando getDeclaredFieldtruque no JDK 8u131 no Linux x64, incluindo a produção de hs_err_pid*.loga SIGSEGV.
Jesse Glick

Usar Unsafenão é uma fraude. O OP não está procurando uma solução 'limpa' para um problema de programação. Ele precisa da jvm para travar da maneira mais feia possível. Fazer coisas nativas desagradáveis ​​é o que pode fazer isso acontecer, e é exatamente o que Unsafefaz.
precisa saber é

34

Eu vim aqui porque também me deparei com essa pergunta no The Passionate Programmer , de Chad Fowler. Para aqueles que não têm acesso a uma cópia, a pergunta é formulada como uma espécie de filtro / teste para candidatos que entrevistam para uma posição que exige "realmente bons programadores de Java".

Especificamente, ele pergunta:

Como você escreveria um programa, em Java puro, que causaria uma falha na Java Virtual Machine?

Programei em Java por mais de 15 anos e achei essa pergunta intrigante e injusta. Como outros já apontaram, o Java, como linguagem gerenciada, é projetado especificamente para não falhar . Obviamente, sempre existem erros da JVM, mas:

  1. Após mais de 15 anos de JREs no nível de produção, é raro.
  2. É provável que algum desses erros seja corrigido na próxima versão, então qual é a probabilidade de você, como programador, encontrar e recuperar os detalhes do conjunto atual de interruptores de exibição do JRE?

Como outros já mencionaram, algum código nativo via JNI é uma maneira de travar um JRE. Mas o autor mencionado especificamente em Java puro , então está pronto.

Outra opção seria alimentar os códigos de bytes falsos do JRE; é fácil despejar alguns dados binários de lixo em um arquivo .class e pedir ao JRE para executá-lo:

$ echo 'crap crap crap' > crap.class
$ java crap
Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1668440432 in class file crap

Isso conta? Quero dizer, o próprio JRE não caiu; ele detectou corretamente o código falso, relatou e saiu.

Isso nos deixa com os tipos mais óbvios de soluções, como explodir a pilha por recursão, ficar sem memória heap por meio de alocações de objetos ou simplesmente jogar RuntimeException. Mas isso apenas faz com que o JRE saia com uma StackOverflowErrorexceção ou similar, o que novamente não é realmente um acidente .

Então o que resta? Eu adoraria ouvir o que o autor realmente tinha em mente como uma solução adequada.

Atualização : Chad Fowler respondeu aqui .

PS: é um livro ótimo. Eu peguei o suporte moral enquanto aprendia Ruby.


1
Essas perguntas de entrevista servem como testes decisivos para desenvolvedores Java que já existem há tempo suficiente para 1) testemunhar (muitas) falhas na JVM e 2) tirar algumas conclusões ou, melhor ainda, como (autoproclamados) especialistas em Java tentaram entender o razões subjacentes a uma falha. Chad Fowler também declara em seu livro que programadores Java autoproclamados "não conseguiram nem encontrar a resposta errada", ou seja, não tentaram pensar em toda uma classe de problemas em potencial. A linha inferior: esta questão é segway para "Como evitar falhas na JVM?" o que é claramente ainda melhor saber.
Shonzilla 27/10/12

1
Eu procuraria pessoas que apenas respondessem (como a maioria aqui fez) "excedendo a pilha", system.exit () ou outro desligamento "Normal", pois realmente não entendem a JVM ou a palavra "Crash". Reconhecer (como você fez) que isso é muito anormal é uma maneira muito boa de identificar um programador mais avançado. Concordo com a sua primeira afirmação, considero uma pergunta excelente e totalmente justa a ser feita ou solicitada - aquelas sem respostas concretas são sempre as melhores.
Bill K

20

Esse código travará a JVM de maneiras desagradáveis

import sun.dc.pr.PathDasher; 

public class Crash
{
     public static void main(String[] args)
     {    
        PathDasher dasher = new PathDasher(null) ;
     }
}

1
Obtendo erro de compilação ao usar o JDK 1.7 com este código: Restrição de acesso: O tipo PathDasher não está acessível devido a restrições na biblioteca C: \ Arquivos de Programas \ Java \ jdk1.7.0_51 \ jre \ lib \ rt.jar
realPK

7
Isso lança um InternalErrorno JDK 1.8. A JVM não falha mais.
Sotirios Delimanolis 31/07

18

A última vez que tentei isso faria:

public class Recur {
    public static void main(String[] argv) {
        try {
            recur();
        }
        catch (Error e) {
            System.out.println(e.toString());
        }
        System.out.println("Ended normally");
    }
    static void recur() {
        Object[] o = null;
        try {
            while(true) {
                Object[] newO = new Object[1];
                newO[0] = o;
                o = newO;
            }
        }
        finally {
            recur();
        }
    }
}

Primeira parte do arquivo de log gerado:

#
# An unexpected error has been detected by Java Runtime Environment:
#
#  EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x000000006dad5c3d, pid=6752, tid=1996
#
# Java VM: Java HotSpot(TM) 64-Bit Server VM (11.2-b01 mixed mode windows-amd64)
# Problematic frame:
# V  [jvm.dll+0x2e5c3d]
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
#

---------------  T H R E A D  ---------------

Current thread (0x00000000014c6000):  VMThread [stack: 0x0000000049810000,0x0000000049910000] [id=1996]

siginfo: ExceptionCode=0xc00000fd, ExceptionInformation=0x0000000000000001 0x0000000049813fe8 

Registers:
EAX=0x000000006dc83090, EBX=0x000000003680f400, ECX=0x0000000005d40ce8, EDX=0x000000003680f400
ESP=0x0000000049813ff0, EBP=0x00000000013f2df0, ESI=0x00000000013f0e40, EDI=0x000000003680f400
EIP=0x000000006dad5c3d, EFLAGS=0x0000000000010206

Estou um pouco divertido com o voto negativo, já que essa é uma das duas únicas respostas que mostram como fazê-lo puramente com código Java e inclui o código completo.
Hot Licks

Concordo que um voto negativo é injustificado - este é um acidente real, mas como você responderia à pergunta da entrevista. A menos que você tenha pesquisado e memorizado isso anteriormente, você não poderia dar uma resposta na entrevista e, se pudesse, consideraria uma resposta neutra a ruim de qualquer maneira - não mostra como você abordaria o problema. Espero que o que você fez foi o Google para explorações de bugs do jvm e implemente um que seja uma excelente resposta.
Bill K

@ BillK - Não, o texto acima é inteiramente um trabalho meu, embora eu o tenha criado há vários anos, experimentando várias coisas. Em uma entrevista, eu provavelmente diria "Eu fiz isso, usando try / catch e recursão, mas não posso recitar o código exato agora".
Hot Licks

1
Quais são os detalhes (versão do JDK, qualquer argumento da VM)? Não tenho certeza qual é a versão "11.2-b0". Estou executando isso, mas consome apenas muita CPU.
Stefan Reich

@ Hot Licks: Qual é o conceito no exemplo de falha na JVM? Por que a JVM trava sobre o código. Todo o thread tem thread de pilha separado ...
VJS

15

Uma implementação perfeita da JVM nunca falha.

Para travar uma JVM, além da JNI, você precisa encontrar um bug na própria VM. Um loop infinito apenas consome CPU. A alocação infinita de memória deve causar apenas OutOfMemoryError em uma JVM bem construída. Isso provavelmente causaria problemas para outros encadeamentos, mas uma boa JVM ainda não deve travar.

Se você encontrar um bug no código-fonte da VM e, por exemplo, causar uma falha de segmentação no uso de memória da implementação da VM, poderá travá-lo.


14

Se você deseja travar a JVM - use o seguinte no Sun JDK 1.6_23 ou abaixo:

Double.parseDouble("2.2250738585072012e-308");

Isso ocorre devido a um erro no Sun JDK - também encontrado no OpenJDK. Isso foi corrigido a partir do Oracle JDK 1.6_24 em diante.


10

Depende do que você quer dizer com acidente.

Você pode fazer uma recursão infinita para que fique sem espaço na pilha, mas isso trava "normalmente". Você receberá uma exceção, mas a própria JVM estará lidando com tudo.

Você também pode usar o JNI para chamar código nativo. Se você não fizer isso da maneira certa, poderá travar com força. Depurar essas falhas é "divertido" (acredite, eu tive que escrever uma grande DLL C ++ que chamamos de um applet java assinado). :)


6

O livro Java Virtual Machine de Jon Meyer tem um exemplo de uma série de instruções de bytecode que fizeram com que a JVM fizesse core dump. Não consigo encontrar minha cópia deste livro. Se alguém por aí tiver um, procure e publique a resposta.


5

em winxpsp2 w / wmp10 jre6.0_7

Desktop.open (uriToAviOrMpgFile)

Isso faz com que um thread gerado lance um Throwable não capturado e trava o ponto de acesso

YMMV


5

O hardware quebrado pode travar qualquer programa. Certa vez, um aplicativo travou de forma reproduzível em uma máquina específica enquanto funcionava bem em outras máquinas com a mesma configuração exata. Acontece que a máquina tinha RAM com defeito.


5

maneira mais curta possível :)

public class Crash
{
    public static void main(String[] args)
    {
        main(args);
    }
}

Não bate. Dá erro de tempo de compilação Exception in thread "main" java.lang.StackOverflowError at Test.main. Estou usando jdk1.8.0_65
Quazi Irfan

5

Não é um acidente, mas está mais próximo do que a resposta aceita do uso System.exit

Você pode interromper a JVM chamando

Runtime.getRuntime().halt( status )

De acordo com os documentos: -

"este método não faz com que ganchos de desligamento sejam iniciados e não executa finalizadores não solicitados se a finalização na saída estiver ativada".



4

Se você quiser fingir que ficou sem memória, pode fazer

public static void main(String[] args) {
    throw new OutOfmemoryError();
}

Conheço algumas maneiras de fazer com que a JVM despeje um arquivo de erro chamando métodos nativos (aqueles que são incorporados), mas provavelmente é melhor você não saber como fazer isso. ;)


4

Se você definir uma falha como um processo interrompido devido a uma situação não tratada (por exemplo, nenhuma exceção ou erro do Java), isso não poderá ser feito no Java (a menos que você tenha permissão para usar a classe sun.misc.Unsafe). Esse é o ponto principal do código gerenciado.

Falhas típicas no código nativo acontecem desmarcando os ponteiros para áreas de memória incorretas (endereço nulo ou desalinhado). Outra fonte pode ser instruções ilegais da máquina (códigos de operação) ou sinais não manipulados de chamadas de biblioteca ou kernel. Ambos podem ser acionados se a JVM ou as bibliotecas do sistema tiverem erros.

Por exemplo, código JIT (gerado), métodos nativos ou chamadas do sistema (driver gráfico) podem ter problemas que levam a falhas reais (era bastante comum ocorrer uma falha quando você usava as funções ZIP e elas ficavam sem memória). Nesses casos, o manipulador de falhas da JVM entra em ação e despeja o estado. Também poderia gerar um arquivo principal do sistema operacional (Dr. Watson no Windows e dump principal no * nix).

No Linux / Unix, você pode facilmente travar a JVM enviando um sinal para o processo em execução. Nota: você não deve usar SIGSEGVisso, pois o Hotspot captura esse sinal e o lança novamente como NullPointerException na maioria dos lugares. Portanto, é melhor enviar um SIGBUSpor exemplo.


3

JNI é uma grande fonte de falhas. Você também pode travar usando a interface JVMTI, pois ela também precisa ser gravada em C / C ++.


2

Se você criar um processo de encadeamento que gera infinitamente mais encadeamentos (que geram mais encadeamentos, que ...), você eventualmente causará um erro de estouro de pilha na própria JVM.

public class Crash {
    public static void main(String[] args) {

        Runnable[] arr = new Runnable[1];
        arr[0] = () -> {

            while (true) {
                new Thread(arr[0]).start();
            }
        };

        arr[0].run();
    }
}

Isso me deu a saída (depois de 5 minutos, observe seu carneiro)

An unrecoverable stack overflow has occurred.
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x0000000070e53ed7, pid=12840, tid=0x0000000000101078
#
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# 

1

Se por "travamento" você quer dizer um cancelamento abrupto da JVM, como faria com que a JVM escrevesse em seu hs_err_pid% p.log , você pode fazê-lo dessa maneira.

Defina the-Xmx arg como um valor minúsculo e diga à JVM para forçar uma falha na memória excedente:

 -Xmx10m -XX:+CrashOnOutOfMemoryError

Para ficar claro, sem o segundo argumento acima, isso resultaria no término da jvm com um OutOfMemoryError, mas não "travaria" ou abortaria abruptamente a jvm.

Essa técnica se mostrou útil quando eu estava tentando testar o argumento JVM -XX: ErrorFile, que controla onde esse log hs_err_pid deve ser gravado. Eu encontrei este post aqui, enquanto tentava encontrar maneiras de forçar esse acidente. Mais tarde, quando descobri que o acima funcionava como o mais fácil para minha necessidade, queria adicioná-lo à lista aqui.

Finalmente, FWIW, se alguém puder testar isso quando já tiver um valor -Xms definido em seus argumentos (para um valor maior que o acima), convém remover ou alterar isso também, ou você não sofrerá uma falha, mas simplesmente uma falha na inicialização da jvm, relatando "Tamanho inicial do heap configurado para um valor maior que o tamanho máximo do heap". (Isso não seria óbvio se a JVM fosse executada como serviço, como em alguns servidores de aplicativos. Novamente, isso me mordeu, então eu queria compartilhá-lo.)


0

Se você alterar esse loop for infinito para uma chamada recursiva para a mesma função, receberá uma exceção de estouro de pilha:

public static void main(String[] args) {
    causeStackOverflow();
}

public void causeStackOverflow() {
    causeStackOverflow();
}

0

Estou fazendo isso agora, mas não tenho muita certeza de como ... :-) Às vezes, a JVM (e meu aplicativo) desaparece completamente. Nenhum erro lançado, nada registrado. Passa do trabalho para não funcionar instantaneamente sem aviso.


Comece a verificar seu hardware, especialmente sua memória!
Thorbjørn Ravn Andersen

Infelizmente, é em várias máquinas que, de outra forma, funcionam muito bem. É apenas esse aplicativo em particular que faz isso (e não consome muita memória ou processador).
27430 Brian Knoblauch

0

Mais curto? Use a classe Robot para acionar CTRL + BREAK. Vi isso quando estava tentando fechar meu programa sem fechar o console (ele não tinha a funcionalidade de 'saída').


Pergunta antiga - espero que alguém se beneficie da sua resposta no futuro.
dbmitch

0

Isso conta?

long pid = ProcessHandle.current().pid();
try { Runtime.getRuntime().exec("kill -9 "+pid); } catch (Exception e) {}

Funciona apenas para Linux e Java 9.

Por alguma razão eu não entendo, ProcessHandle.current().destroyForcibly();não mata a JVM e lança java.lang.IllegalStateExceptioncom a mensagem destruir do processo atual não permitido .


0

Correndo para esse problema ao tentar replicar a falha da JVM.

O Jni funciona, mas precisa ser ajustado para diferentes plataformas. Eventualmente, eu uso essa combinação para causar falha na JVM

  1. Inicie o aplicativo com estas opções da JVM -XX:+CrashOnOutOfMemoryError
  2. Use a long[] l = new long[Integer.MAX_VALUE];para acionar o OOM

A JVM falhará e gerará o log de falha.


-2

Se um 'Crash' é algo que interrompe o jvm / programa da finalização normal, uma exceção Un-handled pode fazer isso.

public static void main(String args[]){
   int i = 1/0;
   System.out.print(i); // This part will not be executed due to above  unhandled exception
  }

Então, depende de que tipo de CRASH ?!


3
Lançar uma exceção não é um acidente.
Quazi Irfan

Porém, as exceções de tempo de execução não tratadas são falhas, que ArithmeticExceptionsão
meados
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.