Chaba Content Site

配列とRAM - メモリの仕組み

2025-08-17

配列がメモリ(RAM)にどう保存されるか学んだこと

最初は「配列って変数をまとめただけでしょ?」と思ってたけど、実際のメモリの仕組みを知ると、なぜ配列が高速なのか理解できた。

そもそもデータ構造って何?

データ構造は、コンピュータのRAM(Random Access Memory)にデータを効率的に保存する方法のこと。RAMは単に「メモリ」とも呼ばれる。

今使ってるパソコンには多分8GB(10⁹バイト)くらいのRAMがある。1バイトは8ビットでできてる。

配列がメモリに保存される仕組み

例えば [1, 3, 5] という配列があるとする。でもコンピュータは0と1(ビット)しか理解できない。

# 整数の配列
arr = [1, 3, 5]

# 各数値のバイナリ表現(1バイトで表すと)
# 1 = 00000001
# 3 = 00000011  
# 5 = 00000101

メモリアドレスの仕組みを理解した瞬間

整数は通常4バイト(32ビット)を使う。配列を保存すると:

メモリアドレス | 値
0x1000        | 1  (4バイト)
0x1004        | 3  (4バイト) 
0x1008        | 5  (4バイト)

重要な発見:アドレスが4バイトずつ離れてる!これが「連続的」ってことか。

文字配列の場合

# 文字の配列
chars = ['A', 'B', 'C']

# 文字は1バイト(8ビット)
# メモリでは:
# 0x2000: 'A' (1バイト)
# 0x2001: 'B' (1バイト)
# 0x2002: 'C' (1バイト)

文字は1バイトだから、アドレスは1バイトずつ増える。

なぜ連続メモリが重要なのか

最初は「別にバラバラでもよくない?」と思ってた。でも理解したのは:

  1. 高速アクセス: インデックスから直接アドレスを計算できる

    # arr[i]のアドレス = 先頭アドレス + (i × データサイズ)
    # arr[2]にアクセスしたい場合:
    # アドレス = 0x1000 + (2 × 4) = 0x1008
    
  2. キャッシュ効率: CPUは近くのメモリも一緒に読み込むから、連続してると速い

Pythonで配列のメモリアドレスを見てみる

import sys
import array

# Python配列の要素のメモリ使用量を確認
arr = [1, 3, 5]
for i, val in enumerate(arr):
    print(f"arr[{i}] = {val}, サイズ: {sys.getsizeof(val)}バイト")

# より低レベルなarray moduleを使う
int_array = array.array('i', [1, 3, 5])  # 'i'は符号付き整数
print(f"配列全体のサイズ: {int_array.itemsize * len(int_array)}バイト")
print(f"要素あたりのサイズ: {int_array.itemsize}バイト")

学んだこと・気づいたこと

なぜこの知識が重要か

最初は「実装できればいいじゃん」と思ってたけど:

  1. アルゴリズムの理解: なぜ配列アクセスが O(1) なのか理解できる
  2. 最適化: メモリ局所性を意識したコードが書ける
  3. システム設計: 大規模システムでメモリ効率を考える時に必須
  4. 面接対策: 「なぜ配列は高速なの?」って聞かれた時に答えられる

実践での応用

# メモリ効率の良い二次元配列の作り方
import numpy as np

# NumPyは連続メモリを使うから高速
matrix = np.array([[1, 2, 3], 
                    [4, 5, 6], 
                    [7, 8, 9]])

# Pythonのリストのリストより高速
python_matrix = [[1, 2, 3], 
                 [4, 5, 6], 
                 [7, 8, 9]]

# NumPyの方がキャッシュ効率が良い

まとめ

次は静的配列について詳しく見ていく

Tags: 配列 メモリ RAM