[Atualização contínua] Perguntas básicas da entrevista clássica sobre informática, Dia 1

[Geral] Perguntas básicas da entrevista clássica sobre computador, dia 1

1. A composição do JVM

  1. Carregador de classes (Class Loader): Responsável por carregar classes Java compiladas na JVM e carregar dinamicamente as classes necessárias em tempo de execução.
  2. Área de dados de tempo de execução: É a área de gerenciamento de memória da JVM, incluindo principalmente a área de método, heap, pilha, contador de programa, etc.
  3. Mecanismo de Execução: Responsável por executar instruções de bytecode, que podem ser implementadas por intérpretes, compiladores just-in-time (JIT), etc.
  4. Coletor de Lixo: Responsável por gerenciar automaticamente a alocação e liberação de memória heap e reciclar a memória de objetos inúteis.
  5. Interface nativa: permite que o código Java chame código escrito em C, C++ local e outras linguagens.
  6. JNI (Java Native Interface): permite que o código Java interaja com o código local e chame métodos escritos em C, C++ local e outras linguagens.

2. Compreensão de heap e pilha em jvm

  1. Área de Método: A área de método faz parte da JVM e é usada para armazenar informações estruturais de uma classe, como campos de classe, métodos, pools de constantes, variáveis ​​estáticas, etc. É uma área compartilhada por todos os threads. Na especificação da JVM, não há uma disposição clara para a implementação da área de método. Diferentes implementações de JVM podem ter diferentes implementações da área de método.
  2. Heap: O heap é a área da JVM onde as instâncias dos objetos são armazenadas.É a área de memória alocada para objetos criados no programa Java. O heap é uma área compartilhada por todos os threads. Um heap é criado quando a JVM é iniciada e o tamanho do heap pode ser ajustado por meio de parâmetros de inicialização. A pilha é dividida em geração jovem e geração velha, e a geração jovem é dividida em espaço Éden e espaço Sobrevivente (De e Para).
  • Espaço Éden: A alocação inicial de objetos é realizada no espaço Éden. Quando o espaço Eden está cheio, o Minor GC é acionado e os objetos sobreviventes são copiados para o espaço Survivor.
  • Espaço Sobrevivente: armazena objetos que sobreviveram ao espaço Éden.Quando o espaço Sobrevivente está cheio, o GC Menor é acionado e os objetos sobreviventes são copiados para outro espaço Sobrevivente, e o espaço Sobrevivente atual é limpo ao mesmo tempo.
  • Geração antiga: armazena objetos de longa duração.Quando a geração antiga está cheia, o Full GC é acionado.
  1. Pilha: A pilha é uma área privada de thread na JVM, usada para armazenar variáveis ​​locais de métodos, pilhas de operandos, valores de retorno de métodos, informações de tratamento de exceções, etc. Cada thread cria um quadro de pilha ao executar um método. O quadro de pilha armazena as variáveis ​​locais do método, a pilha de operandos e outras informações. À medida que os métodos são chamados e retornados, os frames da pilha são enviados e exibidos.
  2. Contador de programa: O contador de programa é uma área privada de thread na JVM que é usada para registrar o endereço das instruções de bytecode executadas pelo thread atual. Cada thread possui um contador de programa independente, que aponta para a instrução em execução no momento. O valor do contador de programa do thread atual é salvo e restaurado quando o thread é trocado. O contador do programa é privado do thread, o estouro de memória não pode ocorrer e a coleta de lixo não é executada.

3. Três maneiras de carregar classes Java

O carregamento da classe Java refere-se ao processo de carregamento do arquivo de bytecode de uma classe na JVM e inicialização e conexão da classe. Existem três maneiras de carregar classes Java:

  1. Carregamento implícito (carregamento implícito de classe): Quando o programa usa a palavra-chave new para criar um objeto ou chama um método estático ou variável estática durante a execução, a JVM carrega automaticamente a classe correspondente. Este é o método de carregamento de classe mais comum e também o método de carregamento de classe padrão.
  2. Carregamento explícito (carregamento explícito de classe): Use o método Class.forName() para carregar explicitamente a classe. O método Class.forName() carregará a classe com base no nome totalmente qualificado da classe fornecida (incluindo o nome do pacote) e retornará o objeto Class correspondente. Este método pode carregar classes dinamicamente e decidir qual classe carregar com base nas condições de tempo de execução.
  3. Carregamento passivo (carregamento passivo de classe): Quando uma classe é referenciada, mas não é realmente usada, a classe não será carregada. A classe só será carregada quando for realmente usada. Cenários comuns de carregamento passivo incluem referência a campos estáticos da classe pai por meio de subclasses, referência a classes por meio de definições de array, constantes armazenadas no pool de constantes da classe chamadora durante a fase de compilação, etc.

4. Conte-me sobre sua compreensão do mecanismo de delegação pai em Java.

O mecanismo de delegação pai é um dos mecanismos de carregamento de classe Java. Sua ideia central é que quando um carregador de classes precisar carregar uma classe, ele primeiro a delegará ao carregador de classes pai para tentar carregá-la. Somente quando o carregador de classes pai não puder carregar a classe, ela será carregada pela classe atual carregador. Isso pode garantir a exclusividade e a segurança da classe e evitar carregamentos e carregamentos repetidos de código malicioso. O mecanismo de delegação pai desempenha um papel importante em Java, permitindo o compartilhamento e a reutilização de classes.

5. Por favor, diga-me o que você entende de gc.

GC (Garbage Collection) é um mecanismo automático de gerenciamento de memória usado para recuperar automaticamente o espaço de memória ocupado por objetos que não são mais usados. Ele completa o processo de coleta de lixo por meio de etapas como marcação, limpeza e compactação. Os programadores não precisam acioná-lo manualmente, ele é executado automaticamente pelo coletor de lixo da JVM. A codificação razoável e o gerenciamento de memória podem maximizar a função do GC e melhorar o desempenho e a estabilidade do programa.

6. Como expandir a capacidade do hashmap

Quando o HashMap insere elementos, ele julgará se precisa expandir de acordo com o fator de carga. O fator de carga refere-se à relação entre o número de elementos armazenados na tabela hash e a capacidade real.

Quando o fator de carga do HashMap exceder o limite definido (o padrão é 0,75), a operação de expansão será acionada. A expansão criará uma nova tabela hash maior e redistribuirá os elementos originais para a nova tabela hash para reduzir conflitos de hash e melhorar a eficiência da consulta.

O processo de expansão do HashMap inclui aproximadamente as seguintes etapas:

  1. Crie uma nova tabela hash com o dobro da capacidade da tabela hash original. A capacidade da nova tabela hash é geralmente escolhida como a potência de 2 que é mais próxima e maior que a capacidade original.
  2. Percorra cada intervalo na tabela hash original, recalcule o valor hash dos elementos no intervalo e atribua-os ao intervalo correspondente na nova tabela hash. Esta etapa recalcula o valor hash e a posição do índice do elemento para garantir que a posição do elemento na nova tabela hash seja alterada.
  3. Defina a nova tabela hash como a tabela hash atual e a tabela hash original se tornará um objeto de lixo aguardando a coleta de lixo.

A operação de expansão pode ter certo impacto no desempenho porque os hashes precisam ser recalculados e os elementos realocados. Para reduzir a frequência de expansão da capacidade, você pode controlar o equilíbrio entre a capacidade e o desempenho do HashMap ajustando o fator de carga. Um fator de carga menor fará com que a tabela de hash se expanda mais rapidamente, mas ocupará mais espaço de memória. Um fator de carga maior reduzirá o número de expansões, mas poderá causar mais conflitos de hash.

7. Fale sobre sua compreensão de hashtable e currenthashmap

Hashtable e ConcurrentHashMap são implementações de tabela hash seguras para threads em Java. Eles têm algumas semelhanças em funcionalidade e uso, mas existem algumas diferenças na implementação interna e no desempenho.

  1. Hashtable: Hashtable é a primeira implementação de tabela hash introduzida. É thread-safe e todas as operações são sincronizadas (implementadas por meio da palavra-chave sincronizada). Devido à sincronização, o desempenho do HashTable em um ambiente multithread é relativamente baixo e a segurança do thread só pode ser garantida permitindo que apenas um thread o acesse ao mesmo tempo.
  2. ConcurrentHashMap: ConcurrentHashMap é uma implementação de tabela hash segura para threads de alto desempenho introduzida no Java 5. Atinge a eficiência do acesso simultâneo usando bloqueios de segmento (Segmento). Cada segmento é equivalente a uma pequena HashTable, que pode ser operada de forma independente, e diferentes segmentos podem realizar operações simultâneas de leitura e gravação. Desta forma, na maioria dos casos, diferentes threads podem operar diferentes Segmentos ao mesmo tempo, melhorando a eficiência do acesso simultâneo. ConcurrentHashMap possui alto desempenho e escalabilidade em ambientes simultâneos.
  3. a diferença:
  • Segurança de thread: Hashtable alcança segurança de thread por meio de sincronização, enquanto ConcurrentHashMap alcança acesso simultâneo eficiente por meio de bloqueios de segmento (Segment).
  • Desempenho: ConcurrentHashMap tem melhor desempenho que Hashtable em um ambiente multithread e pode suportar maior simultaneidade.
  • Consistência fraca do iterador: o iterador do Hashtable é fortemente consistente, ou seja, não será modificado durante o processo de iteração. O iterador de ConcurrentHashMap é fracamente consistente e pode ser modificado durante o processo de iteração, mas não lançará uma exceção ConcurrentModificationException.

Se você precisar usar uma tabela hash em um ambiente multithread e tiver requisitos de alto desempenho, é recomendado usar ConcurrentHashMap.

Se você estiver em um ambiente de thread único ou quando os requisitos de desempenho não forem altos, você poderá usar HashTable.

8. Vamos falar sobre o handshake de três vias e a onda de quatro vias do TCP.

TCP (Transmission Control Protocol) é um protocolo de transmissão de rede confiável e orientado a conexão. Ao estabelecer e fechar uma conexão TCP, são necessários um handshake de três vias e quatro ondas.

O processo de handshake triplo é o seguinte:

  1. O primeiro handshake: o cliente envia um segmento TCP com o flag SYN (sincronização) ao servidor, solicitando o estabelecimento de uma conexão. Neste ponto o cliente entra no estado SYN_SENT.
  2. Segundo handshake: Após receber a solicitação do cliente, o servidor responde ao cliente com um segmento de mensagem com flags SYN e ACK (confirmação). Neste ponto, o servidor entra no estado SYN_RECEIVED.
  3. Terceiro handshake: Após receber a resposta do servidor, o cliente envia novamente ao servidor um segmento de mensagem com a flag ACK, indicando que a conexão foi estabelecida. Neste ponto, a conexão é estabelecida, tanto o cliente quanto o servidor entram no estado ESTABLISHED e a transmissão de dados pode começar.

O processo de handshake de quatro vias é o seguinte:

  1. A primeira onda: o cliente envia um segmento com flag FIN (end) para o servidor, indicando que o cliente não enviará mais dados. O cliente entra no estado FIN_WAIT_1.
  2. A segunda onda: Após receber a solicitação final do cliente, o servidor envia ao cliente um segmento de mensagem com um sinalizador ACK, indicando que o servidor recebeu a solicitação final. Neste ponto o servidor entra no estado CLOSE_WAIT.
  3. A terceira onda: o servidor envia ao cliente um segmento com a flag FIN, indicando que o servidor não enviará mais dados. O servidor entra no estado LAST_ACK.
  4. A quarta onda: Após receber a solicitação de término do servidor, o cliente envia ao servidor um segmento de mensagem com um sinalizador ACK, indicando que o cliente recebeu a solicitação de término. O cliente entra no estado TIME_WAIT e aguarda um período de tempo antes de fechar a conexão. Após o servidor receber o ACK, ele fecha a conexão e entra no estado CLOSED.

Através do handshake de três vias, o cliente e o servidor estabelecem uma conexão confiável; através da onda de quatro vias, ambas as partes completam a transmissão de dados e fecham a conexão com segurança. Isso garante uma transmissão confiável de dados e uma liberação normal de conexões.

9. Fale sobre a diferença entre tcp e udp

TCP (Protocolo de Controle de Transmissão) e UDP (Protocolo de Datagrama de Usuário) são dois protocolos da camada de transporte comumente usados. Eles têm as seguintes diferenças em características e cenários aplicáveis.

  1. Conectividade:
  • TCP é um protocolo orientado a conexão que estabelece uma conexão por meio de um handshake de três vias e fornece transmissão de dados confiável, ordenada e orientada a fluxo de bytes. O TCP garante integridade e confiabilidade dos dados e é adequado para cenários que exigem alta precisão dos dados.
  • UDP é um protocolo sem conexão que não requer o estabelecimento de uma conexão e envia pacotes de dados diretamente. O UDP fornece um método de transmissão de dados simples e sem congestionamentos, adequado para cenários que exigem alto desempenho em tempo real, mas requisitos de confiabilidade relativamente baixos.
  1. Características de transmissão de dados:
  • O TCP fornece transmissão de dados confiável, garantindo que os dados cheguem em ordem e não sejam perdidos por meio do número de sequência e do mecanismo de confirmação. O TCP também fornece mecanismos de controle de fluxo e controle de congestionamento para evitar congestionamento na rede e perda de dados.
  • O UDP fornece transmissão de dados não confiável e os pacotes de dados podem ser perdidos, duplicados ou fora de serviço. O UDP não possui mecanismo de controle de fluxo e controle de congestionamento, e a velocidade de transmissão de dados é mais rápida, mas a confiabilidade dos dados não é garantida.
  1. Tamanho do datagrama:
  • O TCP não tem limite máximo fixo de tamanho de datagrama e pode transmitir grandes quantidades de dados, tornando-o adequado para grandes transferências de arquivos.
  • O UDP tem um tamanho de datagrama limitado (64 KB) e é adequado para transmitir pacotes de dados menores.
  1. eficiência:
  • Embora o TCP garanta confiabilidade, ele introduzirá um grande atraso e a velocidade de transmissão de dados será relativamente lenta.
  • O UDP não possui mecanismo de controle de congestionamento e retransmissão do TCP e sua eficiência de transmissão é maior, porém, devido à sua baixa confiabilidade, não é adequado para cenários que exigem alta precisão dos dados.

10. A diferença entre arrayList e LinkedList

ArrayList e LinkedList são classes de coleção comumente usadas em Java. Eles têm as seguintes diferenças:

  1. Estrutura de implementação interna:
  • A camada inferior de ArrayList é implementada usando um array, e os elementos podem ser acessados ​​e modificados rapidamente por meio de indexação.
  • A camada subjacente do LinkedList é implementada usando uma lista duplamente vinculada. Cada nó contém o valor do elemento atual e uma referência aos nós anteriores e seguintes.
  1. Operações de inserção e exclusão:
  • ArrayList é menos eficiente para operações de inserção e exclusão porque outros elementos precisam ser movidos para preencher as posições excluídas ou inseridas.
  • LinkedList é mais eficiente para operações de inserção e exclusão e só precisa modificar o ponteiro do nó.
  1. Acesso aleatório:
  • ArrayList suporta acesso aleatório, ou seja, acesso direto aos elementos por meio de índices, e a complexidade de tempo é O(1).
  • LinkedList não suporta acesso aleatório e precisa ser percorrido do nó principal até o local de destino, com uma complexidade de tempo de O(n).
  1. Uso de memória:
  • ArrayList requer espaço de armazenamento contínuo na memória, portanto, ao inserir e excluir elementos, o array pode precisar ser expandido e copiado, o que ocupa uma grande quantidade de espaço de memória.
  • LinkedList usa uma estrutura de lista vinculada na memória. Cada nó só precisa armazenar referências ao elemento atual e aos nós anteriores e seguintes, e ocupa um espaço de memória relativamente pequeno.

Se você precisar de acesso aleatório frequente e não tiver requisitos de alto desempenho para operações de inserção e exclusão, poderá escolher ArrayList. Se forem necessárias operações frequentes de inserção e exclusão e os requisitos de desempenho para acesso aleatório não forem altos, você poderá escolher LinkedList. Ao escolher qual classe de coleção usar, você precisa avaliá-la com base em cenários e necessidades específicas de aplicação.

Acho que você gosta

Origin blog.csdn.net/godnightshao/article/details/132722601
Recomendado
Clasificación