Como o uso de memória de um objeto inteiro escrito em Java se compara \ com o uso de memória de um objeto inteiro escrito em C ++? A diferença é insignificante? Não faz diferença? Uma grande diferença? Eu estou supondo que é o mesmo porque um int é um int, independentemente do idioma (?)
A razão pela qual perguntei isso é porque estava lendo sobre a importância de saber quando os requisitos de memória de um programa impedirão que o programador resolva um determinado problema.
O que me fascinou é a quantidade de memória necessária para criar um único objeto Java. Tomemos, por exemplo, um objeto inteiro. Corrija-me se estiver errado, mas um objeto inteiro Java requer 24 bytes de memória:
- 4 bytes para sua variável de instância int
- 16 bytes de sobrecarga (referência à classe do objeto, informações de coleta de lixo e informações de sincronização)
- 4 bytes de preenchimento
Como outro exemplo, uma matriz Java (que é implementada como um objeto) requer 48 + bytes:
- 24 bytes de informações do cabeçalho
- 16 bytes de sobrecarga de objeto
- 4 bytes de comprimento
- 4 bytes para preenchimento
- mais a memória necessária para armazenar os valores
Como esses usos de memória se comparam ao mesmo código escrito em C ++?
Eu costumava ignorar o uso de memória dos programas C ++ e Java que escrevi, mas agora que estou começando a aprender sobre algoritmos, estou apreciando mais os recursos do computador.
fonte
int
? Nesse caso, você deve compará-lo comint
Java, nãoInteger
- desde que suas entradas C ++ sejam 32 bits.Respostas:
Depende da plataforma e implementação.
O C ++ garante que o tamanho de
char
seja exatamente um byte e com pelo menos 8 bits de largura. Então, o tamanho de ashort int
é pelo menos 16 bits e não menor quechar
. O tamanho de umint
é pelo menos tão grande quanto o tamanho deshort int
. O tamanho delong int
é pelo menos 32 bits e não menor que int.sizeof(char) == 1; sizeof(long int) >= sizeof(int) >= sizeof(short int) >= sizeof(bool) >= sizeof(char).
O modelo de memória real do C ++ é muito compacto e previsível . Por exemplo, não há metadados em objetos, matrizes ou ponteiros. Estruturas e classes são contíguas, assim como as matrizes, mas o preenchimento pode ser colocado onde necessário e necessário.
Francamente, porém, essa comparação é tola na melhor das hipóteses, pois o uso da memória Java depende mais da implementação do Java do que do código executado.
fonte
int32_t
.A maioria das respostas parece estar ignorando alguns pontos bastante importantes.
Primeiro, em uma enorme quantidade de Java, você praticamente nunca vê uma matéria
int
- prima - quase todo o uso é útilInteger
; portanto, o fato de que umaint
pode ter (aproximadamente) o mesmo tamanho de umaint
em C ou C ++ é quase irrelevante, exceto por isso ( na minha experiência, pequena) porcentagem de código que usa apenas emint
vez deInteger
.Segundo, o tamanho dos objetos individuais não tem quase nada a ver com o espaço ocupado pela memória de um programa como um todo. Em Java, a pegada de memória do programa está relacionada principalmente à forma como o coletor de lixo foi ajustado. Na maioria dos casos, o GC é ajustado para maximizar a velocidade, o que (em grande parte) significa executá-lo com a menor frequência possível.
Não tenho um link à mão no momento, mas houve alguns testes mostrando que o Java pode rodar na mesma velocidade que o C, mas para isso, é necessário executar o GC raramente o suficiente para que ele use cerca de 7 vezes mais memória. Isso não ocorre porque objetos individuais são 7 vezes maiores, mas porque o GC pode ficar muito caro se você o fizer com muita frequência. Pior, o GC só pode liberar memória quando pode "provar" que não há mais nenhuma maneira de acessar um objeto, e não simplesmente quando você sabe que acabou de usá-lo. Isso significa que, mesmo que você execute o GC com mais frequência para minimizar o uso de memória, provavelmente ainda poderá planejar que um programa típico tenha um espaço de memória maior. Em um caso como esse, você pode reduzir o fator para 2 ou 3 em vez de 7. Mesmo que você exagere drasticamente, no entanto, não1 .
Dependendo da situação, há outro fator que pode ou não ser significativo: a memória ocupada pela própria JVM. Isso é mais ou menos fixo, portanto, como uma porcentagem, pode ser enorme se o aplicativo não precisar de muito armazenamento próprio ou pode ser minúsculo se o aplicativo precisar armazenar muito. Pelo menos na minha máquina, até o aplicativo Java mais trivial parece ocupar algo entre 20 e 25 megabytes (pode ser superior a 1000x para programas triviais, ou quase incomensuravelmente pequeno para grandes).
1 Isso não quer dizer que ninguém possa escrever Java com uma pegada tão próxima do que você obteria com C ++. É apenas dizer que apenas ter o mesmo número / tamanho de objetos e executar o GC com muita frequência não o levará lá como regra.
fonte
Integer
(por que usariam?) Em vez deint
. Somente coleções genéricas não têm escolha a não ser usarInteger
devido ao apagamento de tipo, mas se você se importa, poderá substituí-las por uma implementação especializadaint
ou qualquer tipo primitivo de que você precisa. E depois há boxe temporário para passar pelo código genérico de quebra automática (por exemplo, tudo o que requer umObject[]
). Além disso, você tem fontes para a sobrecarga de espaço do GC? Realmente não duvido, estou apenas curioso.Espero que você perceba que tudo isso é profundamente definido pela implementação, tanto para Java quanto para C ++. Dito isto, o modelo de objetos de Java requer bastante espaço.
Objetos C ++ não (geralmente) precisam qualquer armazenamento, exceto o que os membros precisam. Observe que (diferente do Java, onde tudo o que é definido pelo usuário é um tipo de referência), o código do cliente pode usar objetos como tipo de valor ou como tipos de referência, ou seja, um objeto pode armazenar um ponteiro / referência para outro objeto ou armazenar diretamente o objeto sem indireção. Um ponteiro adicional por objeto é necessário se houver algum
virtual
método, mas várias classes úteis são projetadas para se dar bem sem polimorfismo e não precisam disso. Não há metadados do GC nem bloqueio por objeto. Assim, osclass IntWrapper { int x; public: IntWrapper(int); ... };
objetos não precisam de mais espaço do que o plainint
s e podem ser colocados diretamente (ou seja, sem direcionamento) em coleções e outros objetos.Matrizes são complicadas simplesmente porque não existe um equivalente comum pré-fabricado a uma Matriz Java em C ++. Você pode simplesmente alocar um monte de objetos com
new[]
(sem custos indiretos / metadados), mas não há campo de comprimento - a implementação provavelmente armazena um, mas você não pode acessá-lo.std::vector
é uma matriz dinâmica e, portanto, possui sobrecarga adicional e uma interface maior.std::array
e matrizes no estilo C (int arr[N];
), precisa de uma constante em tempo de compilação. Em teoria, deve ser apenas o armazenamento do objeto mais um único número inteiro para o comprimento - mas como você pode obter redimensionamento dinâmico e uma interface completa com muito pouco espaço extra, basta fazer isso na prática. Observe que todas essas, assim como todas as outras coleções, assumem o padrão de armazenar os objetos por valor, economizando indiretamente o espaço e as referências, além de melhorar o comportamento do cache. Você deve armazenar explicitamente ponteiros (inteligentes, por favor) para obter indireção.As comparações acima não são inteiramente justas, porque algumas dessas economias são proporcionadas pela não inclusão de recursos que o Java inclui e seu equivalente em C ++ geralmente é menos otimizado do que o equivalente em Java (*). A maneira comum de implementar
virtual
em C ++ impõe exatamente tanta sobrecarga quanto a maneira comum de implementarvirtual
em Java. Para obter um bloqueio, você precisa de um objeto mutex com todos os recursos, que provavelmente é maior que alguns bits. Para obter a contagem de referência ( nãoequivalente ao GC e não deve ser usado como tal, mas às vezes útil), você precisa de um ponteiro inteligente que adicione um campo de contagem de referência. A menos que o objeto seja construído com cuidado, a contagem de referência, o objeto ponteiro inteligente e o objeto referenciado estejam em locais completamente separados, e mesmo quando você o constrói da maneira correta, o ponteiro compartilhado pode (deve?) Ainda ser dois ponteiros em vez de um. Por outro lado, o bom estilo C ++ não usa esses recursos o suficiente para importar - na prática, os objetos de uma biblioteca C ++ bem escrita usam menos. Isso não significa necessariamente menos uso geral de memória, mas significa que o C ++ tem uma boa vantagem nesse sentido.(*) Por exemplo, você pode receber chamadas virtuais, códigos de hash de identidade e bloquear com apenas uma palavra para alguns objetos (e duas palavras para muitos outros objetos) mesclando as informações de tipo com vários sinalizadores e removendo os bits de bloqueio dos objetos que estão improvável que precise de bloqueios. Consulte Implementação com eficiência de espaço e tempo do Java Object Model (PDF) de David F. Bacon, Stephen J. Fink e David Grove para obter uma explicação detalhada dessa e de outras otimizações.
fonte
Uma planície
int
, em java, ocupa exatamente tanto espaço quanto umaint
em C ++, desde que ambas as implementações usem o mesmo tamanho inteiro e alinhamento de memória.Um int 'objeto' (um número inteiro in a box , ou seja, uma instância da classe
Integer
), carrega toda a sobrecarga de uma instância da classe em Java, portanto é significativamente maior que umint
em C ++. No entanto, se você equipar um objeto em C ++ com os mesmos recursos que os objetos Java vêm prontos para uso (polimorfismo, boxe, coleta de lixo, RTTI), provavelmente terminará com um objeto igual Tamanho.E depois há considerações de otimização; como os modelos de execução e os paradigmas de programação diferem, é improvável que qualquer problema não trivial seja resolvido da mesma forma nos dois idiomas; portanto, comparar o tamanho do armazenamento nesse nível não faz muito sentido.
Sim, os objetos Java carregam mais sobrecarga por padrão do que as classes C ++, mas eles vêm com mais recursos e isso leva a um estilo de programação diferente - um bom programador pode aproveitar as vantagens e desvantagens de qualquer linguagem.
fonte