Adresse mémoire et adressage

Lorsque vous déclarez une variable dans votre programme, comment l'ordinateur la « trouve »-t-il ? Pourquoi un système 32 bits ne peut-il prendre en charge que 4GB de RAM ?

Cette leçon lève le voile sur les adresses mémoire et vous aide à comprendre l'espace d'adressage — la limite fondamentale qui détermine la quantité de mémoire qu'un ordinateur peut utiliser.


Analogie du quotidien : les boîtes aux lettres dans un immeuble d'appartements

Imaginez un immeuble d'appartements où chaque logement possède sa propre boîte aux lettres, et chaque boîte aux lettres est marquée d'un numéro de logement unique.

Quand un coursier livre le courrier, il lui suffit de connaître le numéro de logement (l'adresse) pour déposer précisément la lettre dans la bonne boîte aux lettres. La façon dont le CPU accède à la mémoire est presque exactement la même que celle d'un coursier qui livre le courrier :

  • Chaque unité de mémoire (1 byte)= Une boîte aux lettres
  • Adresse mémoire= le numéro d'unité de la boîte aux lettres (numéroté à partir de 0)
  • Largeur du bus d'adresses= le nombre maximal de chiffres que le numéro d'unité peut avoir (détermine combien de numéros peuvent être attribués au maximum)

Si le numéro d'unité ne comporte que 2 chiffres (00~99), le bâtiment peut avoir au plus 100 boîtes aux lettres. De même, si le bus d'adresses ne fait que 32 bits de large, le CPU peut distinguer au plus 2^32 cellules mémoire distinctes.


L'essence des adresses mémoire

Une adresse n'est qu'un nombre

Du point de vue matériel, la mémoire est une longue rangée de cellules physiques pouvant stocker des 0 et des 1. Chaque cellule stocke 1 octet (8 bits), et chaque cellule a un numéro unique—ce numéro est l'adresse mémoire。

Le CPU lit et écrit en mémoire via un système à trois bus :

  1. Le CPU place l'adresse cible sur lebus d'adressesSur le bus d'adresses—« Je veux trouver la boîte aux lettres 103 »
  2. Le CPU est sur lebus de commandeSur le bus de commande, il envoie un signal « lecture » ou « écriture »—« Donnez-moi ce qu'il y a à l'intérieur » ou « Mettez ceci à l'intérieur. »
  3. La mémoire place les données dans lebus de donnéesSur le bus de données, les données y sont placées (lecture), ou prises depuis le bus de données (écriture).

Pourquoi chaque adresse correspond-elle à 1 octet ?

C'est un choix de conception. Certains premiers ordinateurs utilisaient « l'adressage par mot » (chaque adresse correspond à 2 ou 4 octets), mais les ordinateurs modernes utilisent presque tous l'adressage par octet—l'adressage par octet, où chaque adresse correspond à 1 octet.

L'avantage : traiter des caractères (chaque caractère ASCII occupe 1 octet) est très naturel, sans avoir besoin d'une logique supplémentaire d'alignement et de découpage.

内存地址:  0      1      2      3      4      5      6      7
         +------+------+------+------+------+------+------+------+
内容:    | 0x48 | 0x65 | 0x6C | 0x6C | 0x6F | 0x00 | 0xFF | ... |
         +------+------+------+------+------+------+------+------+
           'H'    'e'    'l'    'l'    'o'    '\0'

一个 32 位整数 0x12345678 在内存中的存储(小端序):
地址:    0      1      2      3
         +------+------+------+------+
内容:    | 0x78 | 0x56 | 0x34 | 0x12 |
         +------+------+------+------+
          低字节在低地址——这就是「小端序」(Little Endian)

Pourquoi un système 32 bits ne peut utiliser au maximum que 4GB de mémoire

Cause directe : la largeur du bus d'adresses

Une adresse 32 bits est un nombre binaire composé de 32 chiffres qui sont des 0 ou des 1.

Le nombre de valeurs distinctes que 32 bits binaires peuvent représenter est :

2^32 = 2 × 2 × 2 × ... (32 fois) =4,294,967,296

C'est approximativement4GB(GigaBytes)。

Si chaque adresse correspond à 1 octet, alors un espace d'adressage 32 bits peut adresser un total de 4,294,967,296 octets = 4 GB.

Démonstration

1 KB  = 2^10 字节 = 1,024 字节
1 MB  = 2^20 字节 = 1,048,576 字节
1 GB  = 2^30 字节 = 1,073,741,824 字节

2^32  = 2^2 × 2^30
      = 4 × 1 GB
      = 4 GB

Par conséquent,32 bits = 4GBCe n'est pas une coïncidence, mais une relation mathématique stricte entre le nombre de bits d'adresse et l'espace adressable.

Analogie : le nombre de chiffres d'un numéro de téléphone

Supposons que les numéros de téléphone d'une ville comportent 8 chiffres (00000000 ~ 99999999). Quel est le nombre maximal de numéros de téléphone différents que cette ville peut avoir ?

10^8 = 100 millions. Si la population dépasse 100 millions, 8 chiffres ne suffisent plus—il faut passer à 9 chiffres.

Même logique : une adresse 32 bits, poussée à sa limite, fait aussi 4GB. Lorsque les besoins en mémoire dépassent 4GB, un système 32 bits est impuissant—c’est pourquoi l’industrie a collectivement migré vers le 64 bits.


Que signifie 64 bits ?

La limite théorique d’un espace d’adressage 64 bits est :

2^64 = 18,446,744,073,709,551,616 octets ≈16 EB(Exaoctets)

Quelle est la taille de ce nombre ?

  • 1 EB = 1 milliard GB
  • 16 EB représentent environ plusieurs centaines de fois le volume de trafic de données généré par l’internet mondial en une seule journée en 2025.
  • Si chaque octet était un grain de sable, 16 EB de sable pourraient remplir environ 2,000 piscines standard.

Actuellement, aucune carte mère grand public ne prend en charge autant de mémoire. Les processeurs 64 bits modernes n’implémentent généralement que 48 lignes d’adresse physiques (adressables jusqu’à 256 TB), et Windows 10 Famille est limité à 128 GB—mais pour le présent et l’avenir prévisible, c’est déjà « suffisant ».

La véritable importance du 64 bits ne réside pas dans la quantité de mémoire que vous pouvez installer, mais plutôt dans ceci :Les logiciels et les systèmes d’exploitation n’ont plus besoin d’élaborer diverses solutions de contournement pour un espace d’adressage insuffisant.(comme PAE—Physical Address Extension—de l’ère 32 bits).


Comparaison de l’espace adressable selon différentes largeurs de bits

Bits d'adresseNombre d'unités adressablesEspace adressableAnalogie parlanteReprésente un dispositif/système
8 bits256256 BLongueur d'un message textePremiers microcontrôleurs
10 bits1,0241 KBUne page de texte brutPremières EEPROM
16 bits65,53664 KBUne nouvelleIntel 8086, 6502
20 bits1,048,5761 MBUn livre d'épaisseur moyenneIntel 8088 (IBM PC)
24 bits16,777,21616 MBUne piste de musique sans pertePremières stations de travail
32 bits4,294,967,2964 GBUn film HDPentium, ARMv7
36 bits68,719,476,73664 GBToutes les données sur un petit NASmode PAE x86
40 bits1,099,511,627,7761 TBLa capacité totale d'un SSD grand publicARMv8 initial
48 bits281,474,976,710,656256 TBLa quantité de données dans un centre de données de taille moyennex86-64 moderne
64 bits~1.84 × 10^1916 EBUn nombre astronomique, dépassant largement les limites actuelles de la mémoire physiqueLimites de l'architecture x86-64 / ARMv8

Remarque : le passage de 32 bits à 64 bits n'est pas un « doublement », mais un saut de 4GB à 16EB—une augmentation dePlus de 4 milliards de fois! La puissance de la croissance exponentielle est pleinement démontrée ici.


Démo interactive : calculateur d'espace d'adressage

Le programme ci-dessous montre systématiquement l'espace adressable correspondant à différentes largeurs de bits d'adresse, et utilise la visualisation pour vous donner une idée intuitive de la croissance exponentielle.

Exemple

"""
Calculateur d'espace d'adressage mémoire (démonstration d'exemple)
Fonction :
1. Calculer l'espace adressable correspondant à n'importe quel nombre de bits d'adresse
2. Afficher le tableau comparatif complet de 8 bits à 64 bits
3. Visualiser la croissance exponentielle
"""

import math

def address_space_to_str(bytes_val):
    """
Convertir le nombre d'octets en un format lisible par l'humain
Pris en charge : B, KB, MB, GB, TB, PB, EB
    """

    if bytes_val == 0:
        return "0 B"

    units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB']
    unit_idx = 0
    value = float(bytes_val)

    # Augmenter les unités niveau par niveau, en gardant les valeurs dans une plage raisonnable
    while value >= 1024 and unit_idx < len(units) - 1:
        value /= 1024
        unit_idx += 1

    if unit_idx == 0:
        return f"{int(value):,} {units[unit_idx]}"
    elif value >= 100:
        return f"{value:,.0f} {units[unit_idx]}"
    elif value >= 10:
        return f"{value:,.1f} {units[unit_idx]}"
    else:
        return f"{value:,.2f} {units[unit_idx]}"


def print_address_space_table(start_bits=8, end_bits=64):
    """
Afficher le tableau de comparaison des espaces d’adressage
:param start_bits: position de bit de départ
:param end_bits: nombre de bits de fin
    """

    print("=" * 85)
    print(Calculateur d’espace d’adressage mémoire - EXEMPLE Principes d’organisation des ordinateurs)
    print("=" * 85)
    print()
    print(f"{'Bits d’adresse':<10} {'nombre d’unités adressables':>20} {'Espace adressable':>18} {'relatif à 32 bits':>15}")
    print("-" * 85)

    # Basé sur 32 bits
    baseline_32 = 2 ** 32

    # Sélectionner les chiffres significatifs pour l’affichage
    key_bits = [8, 10, 12, 14, 16, 18, 20, 24, 28, 30, 32, 36, 40, 44, 48, 52, 56, 60, 64]

    for bits in key_bits:
        if bits < start_bits or bits > end_bits:
            continue

        count = 2 ** bits
        space_str = address_space_to_str(count)

        # Calculer le ratio par rapport à 32 bits
        if bits <= 32:
            ratio = count / baseline_32
            ratio_str = f"1/{int(baseline_32/count)}" if ratio < 1 else "1x"
        else:
            ratio = count / baseline_32
            if ratio >= 1_000_000_000:
                ratio_str = f{ratio/1_000_000_000:,.1f} cent millions de fois
            elif ratio >= 1_000_000:
                ratio_str = f{ratio/1_000_000:,.0f} millions de fois
            elif ratio >= 1_000:
                ratio_str = f"{ratio/1_000:,.0f} mille fois"
            else:
                ratio_str = f"{ratio:,.0f}x"

        print(f"{bits} bits{'':<5} {count:>20,} {space_str:>18} {ratio_str:>15}")

    print("-" * 85)
    print()


def analyze_why_4gb():
    """Analyse détaillée du processus de dérivation pour 32 bits = 4GB"""
    print("=" * 85)
    print("Analyse approfondie : pourquoi 2^32 = 4 GB ?")
    print("=" * 85)
    print()
    print("Étapes de dérivation :")
    print()
    print(" 2^10 = 1,024 → 1 KB")
    print(" 2^20 = 1,024 × 1,024 = 1,048,576 → 1 MB")
    print(" 2^30 = 1,024 × 1,024 × 1,024 → 1 GB")
    print(" = 1,073,741,824 bytes")
    print()
    print("  2^32 = 2^2 × 2^30")
    print("       = 4 × 1,073,741,824")
    print(" = 4,294,967,296 bytes")
    print(" = 4 GB (plus précisément, 4 GiB)")
    print()
    print("Remarque : à proprement parler")
    print("    4 GB  (Gigabyte)  = 4 × 10^9   = 4,000,000,000 byte(décimal)")
    print(4 GiB (Gibibyte) = 4 × 2^30 = 4,294,967,296 bytes (binaire))
    print(Dans le domaine informatique, ce que l'on appelle communément « mémoire 4GB » désigne en réalité 4 GiB.)
    print()


def visualize_growth():
    """Afficher la croissance exponentielle avec un simple diagramme à barres ASCII"""
    print("=" * 85)
    print("Visualisation de la croissance exponentielle (diagramme à barres ASCII, échelle logarithmique)")
    print("=" * 85)
    print()

    bits_list = [8, 16, 20, 24, 28, 32, 36, 40, 48, 64]
    # Utiliser un logarithme pour compresser la plage d'affichage
    for bits in bits_list:
        count = 2 ** bits
        log10 = math.log10(count)
        bar = "=" * int(log10 * 3)  # Chaque unité log10 = 3 signes égaux
        space_str = address_space_to_str(count)
        print(f" {bits:>3} bits |{bar:<60} {space_str}")

    print()
    print(Observation : De 8 bits à 64 bits, la longueur de la barre augmente régulièrement (car elle est sur une échelle logarithmique))
    print(" Mais la valeur réelle croît exponentiellement — de 32 bits à 64 bits, elle a augmenté de plus de 4 milliards de fois !")
    print()


def practical_questions():
    """Problèmes d'application pratique"""
    print("=" * 85)
    print("Application pratique : calculez la quantité de mémoire que votre système peut prendre en charge.")
    print("=" * 85)
    print()

    questions = [
        ("microcontrôleur à l'ancienne avec un bus d'adresses 8 bits", 8),
        (processeur 6502 avec un bus d'adresses 16 bits, 16),
        ("ordinateur portable avec un système d'exploitation 32 bits", 32),
        (serveur 32 bits avec PAE activé (adresse physique 36 bits), 36),
        (Ordinateur domestique moderne 64 bits (adresse physique 48 bits), 48),
        ("Limite théorique de l'architecture 64 bits", 64),
    ]

    for desc, bits in questions:
        space = 2 ** bits
        print(f" {desc}:")
        print(f" ^{bits} = {space:,} byte = {address_space_to_str(space)}")

    print()


# ========== Programme principal ==========
if __name__ == "__main__":
    print_address_space_table(8, 64)
    analyze_why_4gb()
    visualize_growth()
    practical_questions()

    # Supplément : Requête interactive
    print("=" * 85)
    print("Requête personnalisée")
    print("=" * 85)
    print()

    custom_bits = [1, 4, 8, 16, 32, 64, 128]
    for bits in custom_bits:
        space = 2 ** bits
        print(f{bits:>3} adresses de bits → {space:,} adresses)
        if bits >= 128:
            print(f" → {address_space_to_str(space)} (Remarque : ce nombre dépasse déjà de loin le nombre total d'atomes dans l'univers observable!)")
exemple AddressSpaceComputedevice — bloc coulissant + rendu de formule KaTeX + transformation visuelle de la grille CSS Grid

Démo interactive : calculateur d'espace d'adressage

Faites glisser le curseur pour ajuster le nombre de bits d'adresse (1~64), et utilisez KaTeX pour afficher 2nformule en temps réel, avec CSS Grid qui dessine la grille de cellules mémoire (pour 8 bits ou moins, les 256 cellules sont toutes dessinées).

Bouton de préréglage rapide
Curseur de bits d'adresse
8
Zone de rendu de formule KaTeX
Nombre total d'unités adressables
Zone de visualisation de la grille CSS Grid
Visualisation de la grille d'unités mémoire (chaque cellule représente 1 octet)

PAE : la solution de « prolongation de vie » pour les systèmes 32 bits

Avant que le 64 bits ne se généralise, face à la limite de 4GB, Intel a conçu une solution de contournement —PAE (Physical Address Extension)。

PAE étend les lignes d'adresse physique de 32 bits à 36 bits, ce qui permet aux CPU 32 bits d'adresser jusqu'à 2^36 = 64 GB de mémoire physique.

Mais il y a ici une limitation clé :L'espace d'adressage virtuel de chaque processus reste de 32 bits (4GB)Un programme unique est encore limité à au plus 4GB de mémoire. L'avantage de PAE est qu'il permet aux serveurs d'exécuter plus de programmes simultanément, chaque programme utilisant ses propres 4GB.

PAE n'était qu'une solution transitoire ; la véritable solution consistait à passer complètement au 64 bits.


Adresse virtuelle vs. adresse physique

L'« adresse » dont nous avons parlé plus tôt désigne principalementl'adresse physique—la véritable numérotation au niveau matériel sur les modules de mémoire.

Mais dans les systèmes d'exploitation modernes, l'adresse que voit votre programme n'est pas une adresse physique, mais uneadresse virtuelle。

Pourquoi avons-nous besoin d'adresses virtuelles ?

  1. Protection par isolationadresse virtuelle : le programme A ne peut pas lire ni écrire dans la mémoire du programme B (sinon un programme qui plante pourrait corrompre tout le système).
  2. Simplifier la programmationChaque programme pense qu'il possède exclusivement tout l'espace d'adressage (par ex., 0 à 4GB), sans avoir à se soucier des adresses utilisées par les autres programmes.
  3. Gestion flexible de la mémoireLe système d'exploitation peut temporairement écrire sur disque la mémoire peu utilisée (swap/paging) et la relire lorsque c'est nécessaire.

À l'intérieur du CPU, il y a une unité matérielle appeléeMMU (unité de gestion de la mémoire), qui est responsable de traduire les adresses virtuelles en adresses physiques en temps réel.

程序看到的虚拟地址 → [MMU 翻译] → 物理地址 → [地址总线] → 内存条

程序写:  *(0x08048000) = 42
         ↓
MMU 查表: 虚拟页 0x08048 → 物理页 0x1A3F0
         ↓
物理地址: 0x1A3F0000 的内存单元被写入 42

Les adresses virtuelles sont la pierre angulaire de la stabilité des systèmes d'exploitation modernes. Sans les adresses virtuelles et la MMU, un programme lisant ou écrivant hors limites pourrait faire planter tout le système avec un écran bleu — un cauchemar qui se produisait tous les jours à l'époque du DOS.


Comment les adresses mémoire se manifestent dans la programmation

En C/C++, vous pouvez manipuler directement les adresses mémoire (pointeurs). Voici un exemple intuitif :

Exemple

"""
Visualiser les adresses mémoire en Python (exemple de démo)
Bien que Python fasse abstraction des pointeurs sous-jacents, la fonction id() nous donne tout de même un aperçu de la notion d'adresses.
"""

import sys

# Adresses mémoire des types de base
a = 42
b = 42
c = 999
d = 999

print(EXEMPLE Exploration des adresses mémoire : démonstration de id() en Python)
print("=" * 60)
print()

# Python met en cache les petits entiers (-5~256) ; les variables de même valeur pointent vers la même adresse
print("Phénomène de mise en cache des petits entiers :")
print(fa = 42, id(a) = {id(a)} (hexadécimal : 0x{id(a):X}))
print(fb = 42, id(b) = {id(b)} (hexadécimal : 0x{id(b):X}))
print(f" a et b font référence au même objet : {a is b}")
print()

print("Les grands entiers ne sont pas mis en cache :")
print(fc = 999, id(c) = {id(c)} (hexadécimal : 0x{id(c):X}))
print(fd = 999, id(d) = {id(d)} (hexadécimal : 0x{id(d):X}))
print(fc et d font référence au même objet : {c is d} (généralement False, selon l'implémentation de Python))
print()

# Adresse de la chaîne
text = "Hello EXAMPLE"
print(fL'id de la chaîne 'Hello EXAMPLE' : 0x{id(text):X})

# Adresse de la liste et adresses de ses éléments
lst = [10, 20, 30]
print(f"\nliste lst = {lst}")
print(f" L'id de la liste elle-même : 0x{id(lst):X}")
print(fid de lst[0] : 0x{id(lst[0]):X})
print(fid de lst[1] : 0x{id(lst[1]):X})
print(fid de lst[2] : 0x{id(lst[2]):X})

print()
print(Description :)
print(Bien que Python n'expose pas les adresses mémoire physiques, id() renvoie l'identifiant unique de l'objet.)
print("Dans l'implémentation CPython, id() renvoie l'adresse de l'objet en mémoire virtuelle.")
print(Vous pouvez constater que les éléments de liste sont stockés de manière dispersée (non contigus comme les tableaux C).)
print()

# L'illustration du 32 bits vs 64 bits
print("=" * 60)
print("Informations sur le nombre de bits de l'interpréteur Python :")
print(f" sys.maxsize = {sys.maxsize}")
print(f"  2^31 - 1     = {2**31 - 1}")
print(f"  2^63 - 1     = {2**63 - 1}")
print()
if sys.maxsize > 2**32:
    print(fVotre Python est en 64 bits (maxsize > 2^32))
else:
    print(f" Votre Python est en 32 bits (maxsize <= 2^32)")
autres extensions