Qual é a diferença entre um tipo de referência e um tipo de valor em c #?


100

Um cara me fez essa pergunta alguns meses atrás e eu não consegui explicar em detalhes. Qual é a diferença entre um tipo de referência e um tipo de valor em C #?

Eu sei que os tipos de valor são int, bool, float, etc e referência tipos são delegate, interfaceetc. Ou isso é errado, também?

Você pode me explicar de uma forma profissional?


3
Como uma pequena observação, acho que a pergunta é sobre C #, mas na realidade é sobre C # + .NET. Você não pode analisar C # sem analisar .NET. Não vou recolocar a pergunta porque pode haver alguns pontos a serem feitos ao analisar um sem analisar o outro (iteradores e fechamentos, estou olhando para você)
xanatos

@xanatos, é mais apropriadamente uma pergunta sobre a CLI que C #, VB.Net e, Net têm em comum. Deve haver uma tag para CLI, mas CLI é considerada outra coisa. Existe CLR, mas isso é uma implementação, não um padrão.
user34660

Respostas:


172

Seus exemplos são um pouco estranhos porque enquanto int, boole floatsão tipos específicos, interfaces e delegados são tipos de tipo - assim como structe enumsão tipos de tipos de valor.

Escrevi uma explicação dos tipos de referência e tipos de valor neste artigo . Eu ficaria feliz em expandir qualquer detalhe que você achar confuso.

A versão "TL; DR" é pensar qual é o valor de uma variável / expressão de um tipo particular. Para um tipo de valor, o valor é a própria informação. Para um tipo de referência, o valor é uma referência que pode ser nula ou pode ser uma forma de navegar até um objeto que contém a informação.

Por exemplo, pense em uma variável como um pedaço de papel. Ele poderia ter o valor "5" ou "falso" escrito nele, mas não poderia ter minha casa ... ele teria que ter direções para minha casa. Essas direções são equivalentes a uma referência. Em particular, duas pessoas podem ter pedaços de papel diferentes contendo as mesmas instruções para chegar à minha casa - e se uma pessoa seguir essas instruções e pintar minha casa de vermelho, a segunda pessoa também verá essa mudança. Se os dois tivessem apenas fotos separadas da minha casa no papel, então uma pessoa que colorisse o papel não mudaria o papel da outra pessoa.


2
É importante observar que existem três tipos distintos de semântica que algo pode oferecer: semântica imutável, semântica de valor mutável e semântica de referência mutável. Conceitualmente, o tipo de semântica que uma coisa implementa é ortogonal, independentemente de ser armazenada como um objeto heap autônomo ou uma variável / campo (estrutura). Na prática, embora structs que não expõem seus campos possam implementar qualquer tipo de semântica, o fato de .net permitir o compartilhamento promíscuo de referências de heap significa que os objetos de heap não podem implementar semântica de valor mutável.
supercat

Eu não entendi essa parte - while int, bool and float are specific types, interfaces and delegates are kinds of type - just like struct and enum are kinds of value types. O que você quer dizer com int, bool sendo tipos específicos? Tudo em C #, por exemplo, int, bool, float, class, interface, delegate é um tipo (tipo de dados para ser mais preciso). Os tipos de dados são separados como 'Tipo de referência' e 'Tipo de valor' em C #. Então, por que você está dizendo que int é um tipo específico, mas interface é um tipo de tipo?
RBT

2
@RBT: Os tipos de dados não são apenas segregados em "tipo de referência" e "tipo de valor". Eles também são segregados em "classe, estrutura, enum, delegado, interface". inté uma estrutura, stringé uma classe, Actioné um delegado, etc. Sua lista de "int, bool, float, classe, interface, delegado" é uma lista contendo diferentes tipos de coisas, da mesma forma que "10, int" é uma lista contendo diferentes tipos de coisas.
Jon Skeet de

@JonSkeet Possivelmente a resposta neste post é um pouco enganosa então.
RBT

@RBT: Eu diria que está um pouco mal formulado, mas não horrível.
Jon Skeet de

26

Tipo de valor:

Retém algum valor, não endereços de memória

Exemplo:

Struct

Armazenamento:

TL; DR : O valor de uma variável é armazenado onde quer que seja apagado. Variáveis ​​locais residem na pilha, por exemplo, mas quando declaradas dentro de uma classe como um membro, elas residem na pilha fortemente acoplada à classe na qual são declaradas.
Longer : Assim, os tipos de valor são armazenados onde quer que sejam declarados. Ex: into valor de an dentro de uma função como uma variável local seria armazenado na pilha, enquanto o valor de um in intdeclarado como membro em uma classe seria armazenado na pilha com a classe em que é declarado. Um tipo de valor em uma classe tem um tipo de vida que é exatamente o mesmo da classe em que é declarada, exigindo quase nenhum trabalho do coletor de lixo. É mais complicado, porém, eu me referiria ao livro de @JonSkeet " C # In Depth "Memory in .NET "para uma explicação mais concisa.

Vantagens:

Um tipo de valor não precisa de coleta de lixo extra. Ele obtém o lixo coletado junto com a instância em que reside. Variáveis ​​locais nos métodos são limpas na saída do método.

Desvantagens:

  1. Quando um grande conjunto de valores é passado para um método, a variável receptora realmente é copiada, então há dois valores redundantes na memória.

  2. À medida que as aulas são perdidas. Ela perde todos os benefícios do oop

Tipo de referência:

Contém um endereço de memória de um valor, não um valor

Exemplo:

Classe

Armazenamento:

Armazenado na pilha

Vantagens:

  1. Quando você passa uma variável de referência para um método e ela muda, ela realmente muda o valor original, enquanto nos tipos de valor uma cópia da variável fornecida é feita e esse valor é alterado.

  2. Quando o tamanho da variável é maior, o tipo de referência é bom

  3. Como as classes vêm como variáveis ​​de tipo de referência, elas oferecem capacidade de reutilização, beneficiando assim a programação orientada a objetos

Desvantagens:

Mais referências de trabalho ao alocar e desreferências ao ler o valor. Sobrecarga extra para coletor de lixo


5
Não é necessariamente verdade que os tipos de referência são armazenados no heap e os tipos de valor são armazenados na pilha. Leia yoda.arachsys.com/csharp/memory.html se quiser saber mais.
Rhys

1
Existem muitos mal-entendidos nesta resposta. Leia Jeff Richters CLR via C #. Tipos de valor são armazenados na Thread Stack e não estão sujeitos à coleta de lixo (GC) - eles não têm nada a ver com GC. Tipos de referência são armazenados no heap gerenciado e, portanto, estão sujeitos ao GC. Se um Ref Type tem uma referência raiz, ele não pode ser coletado e é promovido pelas gerações, 0, 1 e 2. Se não tiver uma referência raiz, ele pode ser Coletado como Lixo e então passa por este processo chamado Ressurreição, onde é morto e trazido de volta à vida e então finalmente coletado.
Jeremy Thompson

13

Achei mais fácil entender a diferença dos dois se você souber como o computador aloca coisas na memória e o que é um ponteiro.

A referência geralmente está associada a um ponteiro. Ou seja, o endereço de memória onde sua residência variável é realmente segurando um outro endereço de memória do objeto real em um local de memória diferente.

O exemplo que estou prestes a dar é grosseiramente simplificado, então aceite-o com cautela.

Imagine que a memória do computador seja um monte de caixas postais em uma fileira (começando com caixa postal 0001 até caixa postal n) que pode conter algo dentro dela. Se as caixas postais não servirem para você, tente uma tabela de hash ou dicionário ou uma matriz ou algo semelhante.

Assim, quando você faz algo como:

var a = "Olá";

o computador fará o seguinte:

  1. alocar memória (digamos, começando no local de memória 1000 para 5 bytes) e colocar H (em 1000), e (em 1001), l (em 1002), l (em 1003) e o (em 1004).
  2. alocar em algum lugar na memória (digamos no local 0500) e atribuí-lo como a variável a.
    Então, é como um apelido (0500 é um).
  3. atribua o valor naquele local da memória (0500) a 1000 (que é onde a string Hello começa na memória). Portanto, a variável a contém uma referência ao local real da memória inicial da string "Hello".

O tipo de valor manterá a coisa real em seu local de memória.

Assim, quando você faz algo como:

var a = 1;

o computador fará o seguinte:

  1. alocar um local de memória digamos em 0500 e atribuí-lo à variável a (o mesmo apelido)
  2. coloque o valor 1 nele (no local de memória 0500).
    Observe que não estamos alocando memória extra para manter o valor real (1). Portanto, a está realmente mantendo o valor real e é por isso que é chamado de tipo de valor.


@Jon, Bem, isso meio que invalida o que eu estava dizendo, LOL. Mas, como eu disse, é grosseiramente simplificado obter algum entendimento entre os dois tipos que, no meu caso, achei útil. Pelo menos é como eu imaginei em minha mente :).
Jimmy Chandra em

8

Isso é de uma postagem minha em um fórum diferente, cerca de dois anos atrás. Embora a linguagem seja vb.net (em oposição a C #), os conceitos de tipo de valor versus tipo de referência são uniformes em .net e os exemplos ainda são válidos.

Também é importante lembrar que em .net, TODOS os tipos derivam tecnicamente do tipo base Object. Os tipos de valor são projetados para se comportar como tal, mas no final eles também herdam a funcionalidade do tipo base Object.

A. Tipos de valor são apenas isso - eles representam uma área distinta na memória onde um valor discreto é armazenado. Os tipos de valor têm tamanho fixo de memória e são armazenados na pilha, que é uma coleção de endereços de tamanho fixo.

Quando você faz uma declaração como esta:

Dim A as Integer
DIm B as Integer

A = 3
B = A 

Você fez o seguinte:

  1. Criou 2 espaços na memória suficientes para conter valores inteiros de 32 bits.
  2. Colocou um valor de 3 na alocação de memória atribuída a A
  3. Colocou um valor de 3 na alocação de memória atribuída a B, atribuindo-lhe o mesmo valor que o mantido em A.

O valor de cada variável existe discretamente em cada local de memória.

B. Os tipos de referência podem ser de vários tamanhos. Portanto, eles não podem ser armazenados na "Pilha" (lembra, a pilha é uma coleção de alocações de memória de tamanho fixo?). Eles são armazenados no "Heap gerenciado". Ponteiros (ou "referências") para cada item no heap gerenciado são mantidos na pilha (como um endereço). Seu código usa esses ponteiros na pilha para acessar objetos armazenados no heap gerenciado. Portanto, quando seu código usa uma variável de referência, na verdade está usando um ponteiro (ou "endereço" para um local de memória no heap gerenciado).

Digamos que você tenha criado uma classe chamada clsPerson, com uma string Property Person.Name

Nesse caso, quando você faz uma declaração como esta:

Dim p1 As clsPerson
p1 = New clsPerson
p1.Name = "Jim Morrison"

Dim p2 As Person

p2 = p1

No caso acima, a propriedade p1.Name retornará "Jim Morrison", como seria de esperar. A propriedade p2.Name TAMBÉM retornará "Jim Morrison", como você esperaria intuitivamente. Acredito que tanto p1 quanto p2 representam endereços distintos na pilha. No entanto, agora que você atribuiu a p2 o valor de p1, tanto p1 quanto p2 apontam para a MESMA LOCALIZAÇÃO no heap gerenciado.

Agora, considere ESTA situação:

Dim p1 As clsPerson
Dim p2 As clsPerson

p1 = New clsPerson
p1.Name = "Jim Morrison"

p2 = p1

p2.Name = "Janis Joplin"

Nessa situação, você criou uma nova instância da classe person no Managed Heap com um ponteiro p1 na pilha que faz referência ao objeto e atribuiu à propriedade Name da instância do objeto um valor "Jim Morrison" novamente. Em seguida, você criou outro ponteiro p2 na Pilha e o apontou para o mesmo endereço no heap gerenciado que aquele referenciado por p1 (quando você fez a atribuição p2 = p1).

Aí vem a reviravolta. Ao atribuir a propriedade Name de p2 ao valor "Janis Joplin", você está alterando a propriedade Name para o objeto REFERENCED por ambos p1 e p2, de forma que, se você executou o seguinte código:

MsgBox(P1.Name)
'Will return "Janis Joplin"

MsgBox(p2.Name)
'will ALSO return "Janis Joplin"Because both variables (Pointers on the Stack) reference the SAME OBJECT in memory (an Address on the Managed Heap). 

Aquilo fez sentido?

Último. Se você fizer isto:

DIm p1 As New clsPerson
Dim p2 As New clsPerson

p1.Name = "Jim Morrison"
p2.Name = "Janis Joplin"

Agora você tem dois objetos pessoais distintos. No entanto, no minuto em que você fizer ISSO novamente:

p2 = p1

Você agora apontou ambos de volta para "Jim Morrison". (Não tenho certeza do que aconteceu com o Objeto no Heap referenciado por p2... Acho que agora está fora do escopo. Esta é uma daquelas áreas onde espero que alguém possa me esclarecer...). -EDIT: ACREDITO que é por isso que você definiria p2 = Nada OU p2 = Novo clsPerson antes de fazer a nova atribuição.

Mais uma vez, se você agora fizer ISSO:

p2.Name = "Jimi Hendrix"

MsgBox(p1.Name)
MsgBox(p2.Name)

Ambos os msgBoxes agora retornarão "Jimi Hendrix"

Isso pode ser muito confuso um pouco, e direi uma última vez, posso ter alguns dos detalhes errados.

Boa sorte, e espero que outros que sabem melhor do que eu apareçam para ajudar a esclarecer algumas coisas. . .


Não sei por que você não recebeu nenhum voto positivo. Boa resposta, me ajudou a entender com exemplos claros e simples.
Harry de

Quanto aos conceitos de tipo de valor vs. tipo de referência são uniformes em todo .net, eles são realmente definidos na especificação Common Language Infrastructure (CLI), Ecma padrão 335 (também um padrão ISO). Esse é o padrão para a parte padrão do .Net. O padrão Ecma 334 (também um padrão ISO) é a linguagem C # e afirma explicitamente que as implementações C # devem contar com a CLI ou oferecer suporte a uma maneira alternativa de obter os recursos CLI mínimos exigidos por este padrão C # . O VB.Net, entretanto, não é um padrão, ele é propriedade da Microsoft.
user34660

5

tipo de dados de valor e tipo de dados de referência

1) valor (contém os dados diretamente), mas referência (refere-se aos dados)

2) em valor (cada variável tem sua própria cópia), mas
em referência (mais de uma variável pode se referir a alguns objetos)

3) em valor (a variável de operação não pode afetar outra variável), mas em referência (a variável pode afetar outras)

4) os tipos de valor são (int, bool, float), mas os tipos de referência são (array, objetos de classe, string)


2

Tipo de valor:

  • Tamanho de memória fixo.

  • Armazenado na memória Stack.

  • Contém o valor real.

    Ex. int, char, bool, etc ...

Tipo de referência:

  • Memória não fixa.

  • Armazenado na memória Heap.

  • Armazena o endereço de memória do valor real.

    Ex. string, array, classe, etc ...


1

"Variáveis ​​baseadas em tipos de valor contêm valores diretamente. Atribuir uma variável de tipo de valor a outra copia o valor contido. Isso difere da atribuição de variáveis ​​de tipo de referência, que copia uma referência para o objeto, mas não o próprio objeto." da biblioteca da Microsoft.

Você pode encontrar uma resposta mais completa aqui e aqui .


1
Não gosto dessa explicação, porque parece que a atribuição funciona de maneira diferente para tipos de referência e tipos de valor. Não é verdade. Em ambos os casos, torna o valor da variável "destino" igual à expressão - o valor é copiado. A diferença está em qual é esse valor - para tipos de referência, o valor que é copiado é uma referência. No entanto, esse ainda é o valor da variável.
Jon Skeet de

Concordo com você e já sabia que poderia ser diferente, como você pode ler neste artigo . Mas, estou apenas repassando o guia da Microsoft sobre o assunto e também como você costuma ler nos livros. Por favor, não me culpe! :)
Lucas S.

Claro ... há muitos pedaços de documentação do MSDN onde uma falha pode ser encontrada :)
Jon Skeet

1

Às vezes, as explicações não ajudam, especialmente para os iniciantes. Você pode imaginar o tipo de valor como um arquivo de dados e o tipo de referência como um atalho para um arquivo.

Portanto, se você copiar uma variável de referência, você apenas copiará o link / ponteiro para um dado real em algum lugar da memória. Se você copiar um tipo de valor, você realmente clonará os dados na memória.


0

Isso provavelmente está errado de maneiras esotéricas, mas, para torná-lo simples:

Tipos de valor são valores que são passados ​​normalmente "por valor" (copiando-os). Os tipos de referência são passados ​​"por referência" (fornecendo, assim, um ponteiro para o valor original). Não há nenhuma garantia pelo padrão .NET ECMA de onde essas "coisas" são salvas. Você poderia construir uma implementação do .NET sem pilha ou sem empilhamento (o segundo seria muito complexo, mas provavelmente poderia, usando fibras e muitas pilhas)

As estruturas são do tipo de valor (int, bool ... são estruturas ou pelo menos são simuladas como ...), as classes são do tipo de referência.

Os tipos de valor descendem de System.ValueType. O tipo de referência descende de System.Object.

Agora .. No final você tem Tipo de valor, "objetos referenciados" e referências (em C ++ eles seriam chamados de ponteiros para objetos. Em .NET eles são opacos. Não sabemos o que eles são. Do nosso ponto de vista, eles são "alças" para o objeto). Esses últimos são semelhantes aos Tipos de valor (eles são passados ​​por cópia). Portanto, um objeto é composto pelo objeto (um tipo de referência) e zero ou mais referências a ele (que são semelhantes aos tipos de valor). Quando houver zero referências, o GC provavelmente as coletará.

Em geral (na implementação "padrão" do .NET), o tipo de valor pode ficar na pilha (se forem campos locais) ou no heap (se forem campos de uma classe, se forem variáveis ​​em uma função iteradora, se forem variáveis ​​referenciadas por um encerramento, se forem variáveis ​​em uma função assíncrona (usando o CTP Async mais recente) ...). O valor referenciado só pode ir para o heap. As referências usam as mesmas regras que os tipos de valor.

Nos casos de Tipo de Valor que vão para o heap porque estão em uma função iteradora, uma função assíncrona ou são referenciados por um encerramento, se você observar o arquivo compilado, verá que o compilador criou uma classe para colocar essas variáveis , e a classe é construída quando você chama a função.

Agora, não sei escrever coisas longas e tenho coisas melhores para fazer na minha vida. Se você deseja uma versão "precisa" "acadêmica" "correta", leia ISSO:

http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx

Estou procurando por 15 minutos! É melhor do que as versões do msdn, porque é um artigo condensado "pronto para usar".


1
Está errado de maneiras mais do que esotéricas. É fundamentalmente errado, eu diria - porque os valores de tipo de referência ainda são passados ​​por valor; é apenas que o valor é uma referência, não um objeto. Consulte pobox.com/~skeet/csharp/parameters.html . Ah, e as variáveis ​​locais também podem acabar no heap, por exemplo, se forem capturadas ou parte de um bloco iterador.
Jon Skeet de

Blocos de iteradores são convertidos em classes, portanto, "atrás de você", eles são "campos de uma classe". O mesmo vale para fechamentos. Sim ... esqueci de escrever a distinção entre o "ponteiro" (a referência) e o "apontado"
xanatos

@xanatos: Claro, eles são campos de uma classe após a compilação - mas ainda são variáveis ​​locais no código-fonte. Eu também não chamaria as próprias referências de "tipos de valor" - acho que sei de onde você está vindo, mas não acho uma boa ideia turvar as águas dessa maneira.
Jon Skeet de

@jon Sim ... Eles são um terceiro tipo, porque os ponteiros são "opacos" em .net e não derivam de ValueType. Mas eles são mais semelhantes aos tipos de valor do que às referências. Você pode "ref" e "eliminá-los". Tive de turvar as águas porque "alguém" teve de minar o funcionamento dos iteradores.
xanatos de

Olhando para o artigo que agora aponto, descobri: "Existem três tipos de valores: (1) instâncias de tipos de valor, (2) instâncias de tipos de referência e (3) referências. (O código em C # não pode manipular instâncias de tipos de referência diretamente; sempre faz isso por meio de uma referência. No código não seguro, os tipos de ponteiro são tratados como tipos de valor para fins de determinação dos requisitos de armazenamento de seus valores. ) ".
xanatos de

0

A maneira mais simples de pensar em tipos de referência é considerá-los como sendo "IDs de objeto"; as únicas coisas que se podem fazer com um ID de objeto são criar um, copiar um, consultar ou manipular o tipo de um ou comparar dois para igualdade. Uma tentativa de fazer qualquer outra coisa com um ID de objeto será considerada uma abreviação para fazer a ação indicada com o objeto referido por aquele ID.

Suponha que eu tenha duas variáveis ​​X e Y do tipo Car - um tipo de referência. Y passa a conter "ID do objeto # 19531". Se eu disser "X = Y", isso fará com que X mantenha "ID do objeto # 19531". Observe que nem X nem Y seguram um carro. O carro, também conhecido como "ID do objeto # 19531", está armazenado em outro lugar. Quando copiei Y para X, tudo o que fiz foi copiar o número de identificação. Agora suponha que eu diga X.Color = Colors.Blue. Tal declaração será considerada uma instrução para procurar o "objeto ID # 19531" e pintá-lo de azul. Observe que, embora X e Y agora se refiram a um carro azul em vez de amarelo, a declaração não afeta X ou Y, porque ambos ainda se referem ao "objeto ID # 19531", que ainda é o mesmo carro que ele sempre foi.


0

Os tipos de variáveis ​​e valores de referência são fáceis de aplicar e bem aplicados ao modelo de domínio, facilitando o processo de desenvolvimento.

Para remover qualquer mito em torno da quantidade de "tipo de valor", comentarei como isso é tratado na plataforma. NET, especificamente em C # (CSharp) quando chamado de APIS e envia parâmetros por valor, por referência, em nossos métodos, funções e como fazer o correto tratamento das passagens desses valores.

Leia este artigo Valor do tipo de variável e referência em C #


Este é um site de perguntas e respostas apenas em inglês, infelizmente = \. Obrigado por tentar responder, no entanto. Por favor, crie respostas completas, com links apenas como ajuda (mas não como a resposta sustentada completa). Por favor, dê uma olhada em como responder .
Jesse

0

Suponha que vseja uma expressão / variável do tipo valor e ruma expressão / variável do tipo referência

    x = v  
    update(v)  //x will not change value. x stores the old value of v

    x = r 
    update(r)  //x now refers to the updated r. x only stored a link to r, 
               //and r can change but the link to it doesn't .

Portanto, uma variável do tipo valor armazena o valor real (5 ou "h"). Uma varaible do tipo referência armazena apenas um link para uma caixa metafórica onde o valor está.


0

Antes de explicar os diferentes tipos de dados disponíveis em C #, é importante mencionar que C # é uma linguagem fortemente tipada. Isso significa que cada variável, constante, parâmetro de entrada, tipo de retorno e, em geral, toda expressão que avalia um valor, tem um tipo.

Cada tipo contém informações que serão incorporadas pelo compilador ao arquivo executável como metadados que serão usados ​​pelo Common Language Runtime (CLR) para garantir a segurança do tipo ao alocar e recuperar memória.

Se você quiser saber quanta memória um tipo específico aloca, pode usar o operador sizeof da seguinte maneira:

static void Main()
{
    var size = sizeof(int);
    Console.WriteLine($"int size:{size}");
    size = sizeof(bool);
    Console.WriteLine($"bool size:{size}");
    size = sizeof(double);
    Console.WriteLine($"double size:{size}");
    size = sizeof(char);
    Console.WriteLine($"char size:{size}");
}

A saída mostrará o número de bytes alocados por cada variável.

int size:4
bool size:1
double size:8
char size:2

As informações relacionadas a cada tipo são:

  • O espaço de armazenamento necessário.
  • Os valores máximo e mínimo. Por exemplo, o tipo Int32 aceita valores entre 2147483648 e 2147483647.
  • O tipo básico do qual ele herda.
  • O local onde a memória para variáveis ​​será alocada em tempo de execução.
  • Os tipos de operações permitidas.
  • Os membros (métodos, campos, eventos, etc.) contidos pelo tipo. Por exemplo, se verificarmos a definição do tipo int, encontraremos a seguinte estrutura e membros:

    namespace System
    {
        [ComVisible(true)]
        public struct Int32 : IComparable, IFormattable, IConvertible, IComparable<Int32>, IEquatable<Int32>
        {      
            public const Int32 MaxValue = 2147483647;     
            public const Int32 MinValue = -2147483648;
            public static Int32 Parse(string s, NumberStyles style, IFormatProvider provider);    
            ... 
        }  
    }

Gerenciamento de memória Quando vários processos estão sendo executados em um sistema operacional e a quantidade de RAM não é suficiente para mantê-los todos, o sistema operacional mapeia partes do disco rígido com a RAM e começa a armazenar dados no disco rígido. O sistema operacional usará outras tabelas específicas onde os endereços virtuais são mapeados para seus endereços físicos correspondentes para realizar a solicitação. Essa capacidade de gerenciar a memória é chamada de memória virtual.

Em cada processo, a memória virtual disponível é organizada nas 6 seções a seguir, mas pela relevância deste tópico, vamos nos concentrar apenas na pilha e no heap.

Pilha A pilha é uma estrutura de dados LIFO (último a entrar, primeiro a sair), com um tamanho dependente do sistema operacional (por padrão, para máquinas ARM, x86 e x64, o Windows reserva 1 MB, enquanto o Linux reserva de 2 MB a 8 MB dependendo do versão).

Esta seção da memória é gerenciada automaticamente pela CPU. Cada vez que uma função declara uma nova variável, o compilador aloca um novo bloco de memória tão grande quanto seu tamanho na pilha e, quando a função termina, o bloco de memória para a variável é desalocado.

Heap Esta região da memória não é gerenciada automaticamente pela CPU e seu tamanho é maior que a pilha. Quando a nova palavra-chave é chamada, o compilador começa a procurar o primeiro bloco de memória livre que se ajusta ao tamanho da solicitação. e quando o encontra, é marcado como reservado usando a função C embutida malloc () e retorna o ponteiro para aquele local. Também é possível desalocar um bloco de memória usando a função C free () embutida. Este mecanismo causa fragmentação da memória e tem que usar ponteiros para acessar o bloco certo de memória, é mais lento que a pilha para realizar as operações de leitura / gravação.

Tipos personalizados e integrados Embora o C # forneça um conjunto padrão de tipos integrados que representam inteiros, booleanos, caracteres de texto e assim por diante, você pode usar construções como struct, classe, interface e enum para criar seus próprios tipos.

Um exemplo de tipo personalizado usando a construção de estrutura é:

struct Point
{
    public int X;
    public int Y;
};

Tipos de valor e referência Podemos categorizar o tipo C # nas seguintes categorias:

  • Tipos de valor
  • Tipos de referência

Tipos de valor Os tipos de valor derivam da classe System.ValueType e as variáveis ​​desse tipo contêm seus valores na alocação de memória na pilha. As duas categorias de tipos de valor são struct e enum.

O exemplo a seguir mostra o membro do tipo boolean. Como você pode ver, não há referência explícita à classe System.ValueType, isso acontece porque essa classe é herdada pela estrutura.

namespace System
{
    [ComVisible(true)]
    public struct Boolean : IComparable, IConvertible, IComparable<Boolean>, IEquatable<Boolean>
    {
        public static readonly string TrueString;
        public static readonly string FalseString;
        public static Boolean Parse(string value);
        ...
    }
}

Tipos de referência Por outro lado, os tipos de referência não contêm os dados reais armazenados em uma variável, mas o endereço da memória do heap onde o valor está armazenado. As categorias de tipos de referência são classes, delegados, arrays e interfaces.

Em tempo de execução, quando uma variável do tipo de referência é declarada, ela contém o valor null até que um objeto que foi criado usando as palavras-chave new seja atribuído a ela.

O exemplo a seguir mostra os membros do tipo genérico List.

namespace System.Collections.Generic
{
    [DebuggerDisplay("Count = {Count}")]
    [DebuggerTypeProxy(typeof(Generic.Mscorlib_CollectionDebugView<>))]
    [DefaultMember("Item")]
    public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>
    {
        ...
        public T this[int index] { get; set; }
        public int Count { get; }
        public int Capacity { get; set; }
        public void Add(T item);
        public void AddRange(IEnumerable<T> collection);
        ...
    }
}

Caso você queira descobrir o endereço de memória de um objeto específico, a classe System.Runtime.InteropServices fornece uma maneira de acessar objetos gerenciados da memória não gerenciada. No exemplo a seguir, vamos usar o método estático GCHandle.Alloc () para alocar um identificador para uma string e, em seguida, o método AddrOfPinnedObject para recuperar seu endereço.

string s1 = "Hello World";
GCHandle gch = GCHandle.Alloc(s1, GCHandleType.Pinned);
IntPtr pObj = gch.AddrOfPinnedObject();
Console.WriteLine($"Memory address:{pObj.ToString()}");

A saída será

Memory address:39723832

Referências Documentação oficial: https://docs.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=vs-2019


-1

Existem muitos pequenos detalhes sobre as diferenças entre os tipos de valor e os tipos de referência que são declarados explicitamente pelo padrão e alguns deles não são fáceis de entender, especialmente para iniciantes.

Consulte ECMA padrão 33, Common Language Infrastructure (CLI) . A CLI também é padronizada pela ISO. Eu forneceria uma referência, mas para ECMA devemos baixar um PDF e esse link depende do número da versão. Os padrões ISO custam dinheiro.

Uma diferença é que os tipos de valor podem ser encaixotados, mas os tipos de referência geralmente não podem. Existem exceções, mas são bastante técnicas.

Os tipos de valor não podem ter construtores ou finalizadores de instância sem parâmetros e não podem se referir a si mesmos. Referir-se a si mesmo significa, por exemplo, que se houver um tipo de valor Nó, então um membro de não pode ser um . Acho que há outros requisitos / limitações nas especificações, mas se houver, eles não estão reunidos em um só lugar.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.