Tornar estático um método economiza memória em uma classe da qual você terá várias instâncias?

8

Em resposta à resposta de Aaronaught à pergunta em:

Não posso usar apenas todos os métodos estáticos?

Não é usada menos memória para um método estático? Tenho a impressão de que cada instância de objeto carrega sua própria versão executável de uma função de membro não estática.

Independentemente da quantidade de sobrecarga envolvida na chamada de um método estático, independentemente do projeto de OO ruim e possíveis dores de cabeça no caminho, ele não usa menos memória no tempo de execução?

Aqui está um exemplo:

Eu faço um vetor de objetos inicializados com zero. Cada objeto contém um dado (um triângulo que consiste em nove duplos). Cada objeto é preenchido em sequência a partir dos dados lidos de um arquivo .stl. Apenas um método estático é necessário. O design adequado do OO determina que um método que lide diretamente com os dados seja distribuído para cada objeto. Aqui está a solução OO padrão:

foreach(obj in vec) {
  obj.readFromFile(fileName);
}

Cada obj carrega readFromFileo código compilado juntamente com os dados!

A memória é mais uma preocupação do que o desempenho, neste caso, e há MUITOS dados em um sistema restrito.

Soluções:

  1. Método de espaço para nome (ótimo para C ++, mas não possível em Java)
  2. Um método estático na classe obj. O código executável é mantido em um local no tempo de execução. Há uma pequena sobrecarga para chamar o método
  3. Uma classe pai da qual deriva obj, que contém o método privado readFromFile. Chamada com super.callPrivateMethod()que chamadas readFromFile. Desarrumado e ainda um pouco de memória em cada objeto.
  4. Implemente readFromFilefora do escopo do obj, na classe vec ou na classe de chamada. Isso, na minha opinião, quebra o encapsulamento de dados.

Percebo que, para grandes quantidades de dados, um objeto explícito para cada triângulo não é a melhor abordagem. Este é apenas um exemplo.

panlex
fonte
7
Em qual idioma você acha que o código é duplicado para cada instância? Isso não acontece em Java, C #, C ++.
joshp
2
Bem, isso pode acontecer com alguma linguagem dinâmica em sua infância ou como um efeito colateral da reflexão abusada. Mas, em geral, não, um byte não será muito maior que o byte que ele contém.
Matthew Mark Miller
1
A única linguagem que conheço de onde você pode obter esse comportamento de desperdiçar memória é o Javascript, mas mesmo assim você precisaria falhar completamente no OO prototípico para fazer isso. O que você deve fazer no JS é colocar métodos (estáticos e não estáticos) no objeto protótipo, para que todos os objetos herdados desse protótipo compartilhem essa função sem duplicação.
Ixrec
2
Você já pensou em escrever um pequeno programa que cria milhares desses objetos e fazer as medições você mesmo?
Bryan Oakley
1
Não é a resposta para todas as perguntas relacionadas ao OO: injeção de dependência? Se você está preocupado com a sobrecarga de memória você pode simplesmente criar um objeto "protetor" da qual você faz uma instância, que pode ser injetado ....
Pieter B

Respostas:

19

Os métodos não são armazenados por instância, mesmo com métodos virtuais. Eles são armazenados em um único local de memória e apenas "sabem" a qual objeto eles pertencem porque o thisponteiro é passado quando você os chama.

A única memória extra necessária em C ++ é se você estiver usando métodos virtuais, que exigem um único ponteiro extra por instância para apontar para a tabela de métodos virtuais (em Java, é claro, você sempre tem uma classe base com métodos virtuais Object, portanto, é inevitável )

Se funcionasse da maneira que você descreveu, as linguagens OO não seriam muito populares! Sinta-se livre para adicionar quantos métodos você precisar para seus objetos. Isso não afetará o uso de memória.

vrostu
fonte
Há também uma sobrecarga por método virtual para cada classe. E Java é virtual por padrão ...
Deduplicator
1
@ Reduplicador: Isso mesmo, mas você também pode argumentar que há uma sobrecarga por ter funções / métodos em primeiro lugar. Cada função ocupa memória e uma função virtual leva um pouquinho mais (cerca de 4 bytes).
Bart van Ingen Schenau
@BartvanIngenSchenau Ou 8 bytes e para cada classe derivada novamente. Embora ambas as estimativas estão muito subestimando o custo em Java ...
Deduplicator
3
@Duplicador Ainda assim, esse custo é por classe (e por classe derivada), não por instância.
Craig
7

Independentemente da quantidade de sobrecarga envolvida na chamada de um método estático, independentemente do projeto de OO ruim e possíveis dores de cabeça no caminho, ele não usa menos memória no tempo de execução?

Isso é bastante complicado, mas eu diria "principalmente não".


fonte
2

Um método deve ser "estático" (muitos idiomas usam o termo "método de classe", que é muito melhor) se não se referir a uma instância da classe. Deve ser um método de instância se se referir a uma instância da classe.

Tomar uma decisão de design com base na vaga possibilidade de economia de memória em vez do uso adequado de métodos de classe e de instância é uma idéia muito, muito, muito ruim.

gnasher729
fonte
2
Um bom conselho, mas na verdade não responde à pergunta.
perfil completo de Jacques
1
Com a forte suposição de que essa é uma pergunta XY, é verdade.
precisa saber é o seguinte
1

Em princípio, há apenas uma cópia do código, sejam elas funções de membro estáticas ou não:

  • No C ++, você pode verificar isso facilmente, observando a lista de montadores do código gerado.
  • Eu não sou especialista em Java, mas a partir da especificação JNI você pode deduzir a mesma lógica: você pode buscar uma única referência a uma função e chamá-la várias vezes para objetos diferentes (passando uma referência de classe como argumento, bem como o referência de objeto se não for um método estático).

O uso de uma função estática ou não estática, portanto, não altera a área de cobertura da memória.

Na realidade, existe uma diferença muito pequena, tanto no código gerado quanto na memória consumida na pilha durante o tempo de execução da função:

  • Uma chamada para a função não estática requer a passagem de uma referência / ponteiro para o objeto no qual a função / método é aplicada. Isso geralmente requer um envio adicional e instruções pop na sequência de chamadas.
  • Uma chamada para uma função estática não requer essa sobrecarga.

Mas isso é realmente insignificante: estamos falando de uma ou duas instruções da máquina mais ou menos em comparação com o código completo. Portanto, definitivamente não é algo para se preocupar.

A diferença de consumo da pilha no tempo de execução é limitada ao tempo de execução da função, ao tamanho de um ponteiro. Isso também é insignificante, a menos que você esteja pensando em uma função chamada recursivamente um grande número de vezes (vários milhões de vezes).

Concluindo, compartilho totalmente a opinião do gnasher729 : a otimização prematura é a raiz de todo mal. Se a função for independente do objeto, torne-o estático e esse deve ser o único critério.

Christophe
fonte
Eu acredito que o compilador C ++ pode evitar passar a referência para this, se não for usado na função. Em Java, provavelmente o JIT poderia fazer isso.
Oliv
0

É fácil focar em coisas como otimizar o uso da memória ou reduzir linhas de código, mas quando você começa a manter programas que as pessoas usam / interrompem e outros programadores adicionam funcionalidade a ... e possivelmente introduzem bugs ... não que o seu programa original Se houver algum erro que tenha passado dos testes, você verá que o foco na legibilidade / capacidade de manutenção do código pode ser mais importante. Eu poderia criar uma matriz de bits de alta velocidade para rastrear uma série de pontos de dados, mas, a menos que envolva essa matriz de bits em um objeto com acessadores compreensíveis, o próximo programador a tocar nesse código provavelmente não o usará, substituirá ou fará alguma bruxaria hedionda. .

Jamy Spencer
fonte