Como uma espécie de acompanhamento da pergunta chamada Diferenças entre o MSIL e o bytecode Java? , quais são as (principais) diferenças ou semelhança em como a Java Virtual Machine funciona versus como o.NET Framework O Common Language Runtime (CLR) funciona?
Além disso, é o Estrutura .NET CLR uma "máquina virtual" ou não possui os atributos de uma máquina virtual?
Respostas:
Existem muitas semelhanças entre as duas implementações (e na minha opinião: sim, elas são "máquinas virtuais").
Por um lado, ambas são VMs baseadas em pilha, sem noção de "registradores", como estamos acostumados a ver em uma CPU moderna como o x86 ou o PowerPC. A avaliação de todas as expressões ((1 + 1) / 2) é realizada empurrando operandos para a "pilha" e, em seguida, removendo-os da pilha sempre que uma instrução (adicionar, dividir, etc.) precisar consumir esses operandos. Cada instrução envia seus resultados de volta para a pilha.
É uma maneira conveniente de implementar uma máquina virtual, porque praticamente todas as CPUs do mundo têm uma pilha, mas o número de registros geralmente é diferente (e alguns registros são para fins especiais, e cada instrução espera seus operandos em registros diferentes, etc.) )
Portanto, se você for modelar uma máquina abstrata, um modelo puramente baseado em pilha é um bom caminho a percorrer.
Obviamente, máquinas reais não funcionam dessa maneira. Portanto, o compilador JIT é responsável por executar o "registro" das operações do bytecode, essencialmente planejando os registros reais da CPU para conter operandos e resultados sempre que possível.
Então, acho que esse é um dos maiores pontos em comum entre o CLR e a JVM.
Quanto às diferenças ...
Uma diferença interessante entre as duas implementações é que o CLR inclui instruções para criar tipos genéricos e, em seguida, para aplicar especializações paramétricas a esses tipos. Portanto, no tempo de execução, o CLR considera uma Lista <int> como um tipo completamente diferente de uma Lista <>.
Nos bastidores, ele usa o mesmo MSIL para todas as especializações de tipo de referência (para que uma Lista <> use a mesma implementação que uma Lista <Objeto>, com diferentes tipos de conversão nos limites da API), mas cada tipo de valor usa sua própria implementação exclusiva (Lista <int> gera código completamente diferente da Lista <double>).
Em Java, tipos genéricos são apenas um truque de compilador. A JVM não tem noção de quais classes possuem argumentos de tipo e é incapaz de executar especializações paramétricas em tempo de execução.
De uma perspectiva prática, isso significa que você não pode sobrecarregar métodos Java em tipos genéricos. Você não pode ter dois métodos diferentes, com o mesmo nome, diferindo apenas se eles aceitam uma Lista <> ou uma Lista <Data>. Obviamente, como o CLR conhece os tipos paramétricos, não há problemas em lidar com métodos sobrecarregados em especializações de tipos genéricos.
No dia a dia, essa é a diferença que mais noto entre o CLR e a JVM.
Outras diferenças importantes incluem:
O CLR possui encerramentos (implementados como representantes de C #). A JVM suporta fechamentos apenas desde o Java 8.
O CLR possui corotinas (implementadas com a palavra-chave C # 'yield'). A JVM não.
O CLR permite que o código do usuário defina novos tipos de valor (structs), enquanto a JVM fornece uma coleção fixa de tipos de valor (byte, short, int, long, float, double, char, boolean) e permite apenas que os usuários definam novas referências- tipos (classes).
O CLR fornece suporte para declarar e manipular ponteiros. Isso é especialmente interessante porque a JVM e o CLR empregam implementações estritas de coletor de lixo de compactação geracional como estratégia de gerenciamento de memória. Em circunstâncias normais, um GC de compactação rigoroso tem muita dificuldade com ponteiros, porque quando você move um valor de um local de memória para outro, todos os ponteiros (e ponteiros para ponteiros) se tornam inválidos. Mas o CLR fornece um mecanismo de "fixação" para que os desenvolvedores possam declarar um bloco de código dentro do qual o CLR não tem permissão para mover determinados ponteiros. É muito conveniente.
A maior unidade de código na JVM é um 'pacote', como evidenciado pela palavra-chave 'protected', ou possivelmente um JAR (ou seja, Java ARchive), como evidenciado por ser capaz de especificar um jar no caminho de classe e tratá-lo como uma pasta de código. No CLR, as classes são agregadas em 'assemblies', e o CLR fornece lógica para raciocinar e manipular assemblies (carregados em "AppDomains", fornecendo caixas de proteção no nível de sub-aplicativo para alocação de memória e execução de código).
O formato de bytecode CLR (composto de instruções e metadados do MSIL) possui menos tipos de instruções que a JVM. Na JVM, toda operação exclusiva (adicione dois valores int, adicione dois valores flutuantes, etc.) possui sua própria instrução exclusiva. No CLR, todas as instruções MSIL são polimórficas (adicione dois valores) e o compilador JIT é responsável por determinar os tipos dos operandos e criar o código de máquina apropriado. Mas não sei qual é a estratégia preferida. Ambos têm trocas. O compilador HotSpot JIT, para a JVM, pode usar um mecanismo de geração de código mais simples (não precisa determinar os tipos de operandos, porque eles já estão codificados na instrução), mas isso significa que precisa de um formato de bytecode mais complexo, com mais tipos de instruções.
Uso Java (e admiro a JVM) há cerca de dez anos.
Mas, na minha opinião, o CLR é agora a implementação superior, em quase todos os aspectos.
fonte
Sua primeira pergunta é comparar a JVM com o .NET Framework - suponho que você realmente quis comparar com o CLR. Se sim, acho que você poderia escrever um pequeno livro sobre isso ( EDIT: parece que Benji já tem :-)
Uma diferença importante é que o CLR foi projetado para ser uma arquitetura neutra em linguagem, diferente da JVM.
Outra diferença importante é que o CLR foi projetado especificamente para permitir um alto nível de interoperabilidade com o código nativo. Isso significa que o CLR deve gerenciar a confiabilidade e a segurança quando a memória nativa é acessada e modificada, além de gerenciar o empacotamento entre estruturas de dados baseadas em CLR e estruturas de dados nativas.
Para responder à sua segunda pergunta, o termo “máquina virtual” é um termo mais antigo do mundo do hardware (por exemplo, virtualização da IBM da 360 na década de 1960) que costumava significar uma emulação de software / hardware da máquina subjacente para realizar o mesmo tipo de coisas que o VMWare faz.
O CLR é frequentemente chamado de "mecanismo de execução". Nesse contexto, é uma implementação de uma máquina de IL em cima de um x86. Isso também é o que a JVM faz, embora você possa argumentar que há uma diferença importante entre os bytecodes polimórficos do CLR e os bytecodes digitados pela JVM.
Portanto, a resposta pedante à sua segunda pergunta é "não". Mas tudo se resume a como você define esses dois termos.
EDIT: Mais uma diferença entre a JVM e o CLR é que a JVM (versão 6) é muito relutante em liberar memória alocada de volta para o sistema operacional, mesmo onde pode.
Por exemplo, digamos que um processo da JVM seja iniciado e aloque 25 MB de memória do sistema operacional inicialmente. O código do aplicativo tenta alocações que exigem 50 MB adicionais. A JVM alocará 50 MB adicionais do sistema operacional. Depois que o código do aplicativo parar de usar essa memória, ele é coletado como lixo e o tamanho do heap da JVM diminui. No entanto, a JVM liberará apenas a memória alocada do sistema operacional sob determinadas condições circunstâncias muito específicas . Caso contrário, pelo restante da vida útil do processo, a memória permanecerá alocada.
O CLR, por outro lado, libera a memória alocada de volta para o sistema operacional, se não for mais necessário. No exemplo acima, o CLR teria liberado a memória assim que o heap tivesse diminuído.
fonte
O CLR e a JVM são máquinas virtuais.
O .NET Framework e o Java Runtime Environment são o pacote das respectivas VMs e suas bibliotecas. Sem bibliotecas, as VMs são bastante inúteis.
fonte
Mais detalhes sobre as diferenças podem ser encontrados em várias fontes acadêmicas e privadas. Um bom exemplo é o CLR Design Choices .
Alguns exemplos específicos incluem:
fonte
Não é uma máquina virtual, a estrutura .net compila os assemblies no binário nativo no momento da primeira execução:
Na computação, a compilação just-in-time (JIT), também conhecida como tradução dinâmica, é uma técnica para melhorar o desempenho em tempo de execução de um programa de computador. O JIT se baseia em duas idéias anteriores em ambientes de tempo de execução: compilação de bytecode e compilação dinâmica. Ele converte o código em tempo de execução antes de executá-lo nativamente, por exemplo, bytecode em código de máquina nativo. A melhoria de desempenho em relação aos intérpretes se origina do armazenamento em cache dos resultados da tradução de blocos de código, e não apenas da reavaliação de cada linha ou operando cada vez que ele é atendido (consulte Idioma interpretado). Ele também possui vantagens em compilar estaticamente o código no momento do desenvolvimento, pois ele pode recompilar o código, se isso for vantajoso, e pode impor garantias de segurança.
Vários ambientes de tempo de execução modernos, como o .NET Framework da Microsoft, a maioria das implementações de Java e, mais recentemente, o Actionscript 3, contam com a compilação JIT para execução de código em alta velocidade.
Fonte: http://en.wikipedia.org/wiki/Just-in-time_compilation
A adição do .NET framework contém uma máquina virtual, assim como Java.
fonte