Quando o programa cria entidades do tipo referência, como objetos, matrizes etc., o sistema alocará uma peça de memória para o objeto na memória da heap, e o objeto é armazenado nesta peça de memória. Quando esse pedaço de memória não é mais referenciado por nenhuma variável de referência, a peça de memória se torna lixo, aguardando o mecanismo de coleta de lixo ser reciclado. O mecanismo de coleta de lixo tem três características:
O mecanismo de coleta de lixo é responsável apenas pela reciclagem de objetos na memória da heap e não reciclará nenhum recurso físico (como conexões de banco de dados, recursos de arquivo aberto etc.), nem reciclará a memória alocada ao objeto de uma maneira que não seja a maneira de criar um objeto (como a memória aplicada pelo objeto que chama Malloc no método local)
O programa não pode controlar com precisão a operação da coleta de lixo, por isso só pode ser recomendado para a coleta de lixo. Existem dois métodos recomendados: System.GC () e RunTime.GetRuntime (). GC ()
Antes da coleta de lixo, seu método Finalize () sempre será chamado primeiro, mas é o mesmo que o tempo de coleta de lixo, e o método Finalize () também não tem certeza.
Em relação às três características acima, existem três problemas:
1. O trabalho de limpeza deve ser feito manualmente para liberar a memória e outros recursos físicos alocados de uma maneira que não seja a maneira de criar objetos. E tenha cuidado para eliminar as referências de objetos vencidos, caso contrário, a OOM poderá ser causada.
A limpeza manual geralmente usa uma estrutura de código como tentar ... finalmente ...
Exemplos são os seguintes:
importar java.io.fileInputStream; importar java.io.filenotfoundException; importar java.io.ioException; public class manualclear {public static void main (string [] args) {fileInputStream fileInputStream = null; tente {fileInputStream = new FileInputStream ("./ src/manualclear.java"); } catch (filenotfoundException e) {System.out.println (e.getMessage ()); E.PrintStackTrace (); retornar; } tente {byte [] bbuf = novo byte [1024]; int hasRead = 0; tente {while (hasRead = FileInputStream.read (bbuf))> 0) {System.out.println (new String (bbuf, 0, hasRead)); }} catch (ioexception e) {e.printStackTrace (); }} finalmente {try {fileInputStream.close (); } catch (ioexception e) {e.printStackTrace (); }}}}Geralmente, existem três casos de OOM comuns causados pela referência a objetos expirados. Esses três casos geralmente não são fáceis de detectar e não haverá problemas em execução em um curto período de tempo. No entanto, depois de um longo tempo, o número de objetos vazados acabará causando a falha do programa.
Quando a classe gerencia a memória por si só, você deve ter cuidado com vazamentos de memória da seguinte forma:
importar java.util.arrays; importar java.util.EmentStackException; classe pilha {Private Object [] elementos; Tamanho privado int; private estático final int default_inital_capacity = 16; public stack () {elementos = novo objeto [default_inital_capacity]; } public void push (objeto e) {securecapacity (); elementos [tamanho ++] = e; } public object pop () {if (size == 0) {lança new emptyStACKexception (); } retornar elementos [-tamanho]; } vazio privado eSureCapacity () {if (elements.Length == size) {elementos = Arrays.copyof (elementos, 2 * tamanho + 1); }}} classe pública StackDemo {public static void main (string [] args) {pilha pilha = new Stack (); for (int i = 0; i <10000; i ++) {staack.push (new Object ()); } para (int i = 0; i <10000; i ++) {staack.pop (); }}}O motivo dos vazamentos de memória é que, mesmo que outros objetos na pilha não sejam mais referenciados, a matriz de elementos [] na classe de pilha ainda mantém referências a esses objetos, resultando nos objetos que não estão sendo reciclados pela coleta de lixo. Portanto, quando a classe precisa gerenciar a memória por si só, cuidado para que essas referências expiradas mantidas internamente sejam desreferenciadas no tempo. Neste exemplo, somente depois que a pilha for lançada, a exibida será exibida.
elementos [tamanho] = nulo;
O cache deve ter cuidado com vazamentos de memória. Essa situação geralmente é o caso de que, uma vez que o objeto é colocado no cache, é provável que seja fácil esquecer se não for usado por um longo tempo. Geralmente, o wakehashmap pode ser usado para representar o cache. Depois que os itens do cache expiram, eles podem ser excluídos automaticamente. Ou pode ser executado periodicamente por um thread de segundo plano para limpar os itens expirados no buffer.
O registro de ouvintes ou retornos de chamada é melhor exibido para o registro.
2. Não ligue para Finalize () manualmente, é chamado para o coletor de lixo
3. Evite usar o método Finalize (), a menos que seja usado como julgamento da condição final para descobrir que o objeto não foi limpo corretamente; É usado como uma rede de segurança para limpar os recursos do sistema quando limpados manualmente esqueciam chamadas. A limpeza atrasada não deve ser limpa. Se você registrar as informações sobre o recurso de limpeza esquecido ao mesmo tempo, também será conveniente para que os erros sejam descobertos posteriormente e modifiquem o código de limpeza esquecido no tempo; Libere os recursos não muito críticos do sistema obtidos pelo método local no objeto.
Como o método finalize () não é garantido com precisão, é melhor não liberar recursos importantes, mas pode ser usado nos três casos mencionados acima. O primeiro caso é o seguinte:
Classe livro {checkout boolean = false; Public Book (checkout boolean) {this.checkout = checkout; } public void checkin () {checkout = false; } @Override Protected void finalize () lança arremesso {if (checkout) {System.out.println ("erro: check -out"); }}} public class FinalizecheckObjectuse {public static void main (string [] args) {new Book (true); System.gc (); }}Resultados da execução:
ERRO: Confira
O objeto do livro no exemplo deve estar no estado de check -in antes de ser lançado, caso contrário, ele não poderá ser lançado. A implementação no Finalize pode ajudar a descobrir objetos ilegais no tempo, ou mais diretamente, usar uma variável de referência para se referir diretamente a ele na finalização, para que possa entrar novamente no estado de alcance e depois processá-lo novamente.
Outro ponto a ser observado é que, se a subclasse substituir o método finalizado da classe pai, mas esquecer de chamar manualmente super.finalizar ou o processo finalizado da subclasse tem uma exceção, resultando em super.finalizar não sendo executado, o método final da classe pai nunca será chamado.
do seguinte modo:
classe pai {@Override Protected void finalize () lança throwable {System.out.println (getClass (). getName () + "finalize start"); }} classe SON estende o pai {@Override Protected void finalize () lança throwable {System.out.println (getClass (). getName () + "finalize start"); }} classe pública superfinalizeLost {public static void main (string [] args) {new Son (); System.gc (); }}Resultados em execução:
Filho finalize o começo
ou
classe pai {@Override Protected void finalize () lança throwable {System.out.println (getClass (). getName () + "finalize start"); }} classe SON estende o pai {@Override Protected void finalize () lança throwable {System.out.println (getClass (). getName () + "finalize start"); int i = 5 /0; super.finalize (); }} classe pública superfinalizeLost {public static void main (string [] args) {new Son (); System.gc (); }}Resultados da execução:
Filho finalize o começo
Para o segundo caso, você pode usar a estrutura ... finalmente ... para resolvê -la, mas, no primeiro caso, é melhor usar um método chamado Method Guardian. O exemplo é o seguinte
classe parent2 {objeto final privado finalizeguardian = new object () {void protegido finalize () lança throwable {System.out.println ("execute a lógica no método de encerramento da classe pai aqui"); }; };} classe SON2 estende Parent2 {@Override Protected void Finalize () lança Throwable {System.out.println (getClass (). getName () + "Finalize Start"); int i = 5 /0; super.finalize (); }} classe pública FinalizeGuardian {public static void main (string [] args) {new SON2 (); System.gc (); }}Resultados da execução:
Execute a lógica no método de terminação da classe pai aqui
SON2 Finalize Start
Isso garante que as operações necessárias no método final da classe pai sejam executadas.
O exposto acima é tudo sobre este artigo, espero que seja útil para o aprendizado de todos.