2026-02-18 15:52:55 +08:00
|
|
|
|
<template>
|
2026-02-24 00:18:09 +08:00
|
|
|
|
<div class="demo">
|
|
|
|
|
|
<div class="title">🧠 操作系统给每个程序"画饼"</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="scene">
|
|
|
|
|
|
<!-- 程序视角 -->
|
|
|
|
|
|
<div class="view-box">
|
|
|
|
|
|
<div class="view-title">📱 程序以为的内存(虚拟)</div>
|
|
|
|
|
|
<div class="virtual-mem">
|
|
|
|
|
|
<div class="proc-mem wechat">
|
|
|
|
|
|
<div class="proc-label">💬 微信</div>
|
|
|
|
|
|
<div class="mem-blocks">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="n in 4"
|
|
|
|
|
|
:key="n"
|
|
|
|
|
|
class="v-block"
|
|
|
|
|
|
:class="{ filled: wechatProgress >= n * 25 }"
|
|
|
|
|
|
>{{ n }}</div>
|
2026-02-23 01:40:56 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-02-24 00:18:09 +08:00
|
|
|
|
<div class="proc-mem game">
|
|
|
|
|
|
<div class="proc-label">🎮 游戏</div>
|
|
|
|
|
|
<div class="mem-blocks">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="n in 4"
|
|
|
|
|
|
:key="n"
|
|
|
|
|
|
class="v-block game"
|
|
|
|
|
|
:class="{ filled: gameProgress >= n * 25 }"
|
|
|
|
|
|
>{{ n }}</div>
|
2026-02-23 01:40:56 +08:00
|
|
|
|
</div>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
<!-- 映射箭头 -->
|
|
|
|
|
|
<div class="mapping-arrow">
|
|
|
|
|
|
<div class="arrow-text">操作系统偷偷映射 ↓</div>
|
|
|
|
|
|
<div class="mapping-lines">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="(map, idx) in visibleMappings"
|
|
|
|
|
|
:key="idx"
|
|
|
|
|
|
class="map-line"
|
|
|
|
|
|
:class="map.type"
|
|
|
|
|
|
:style="{ animationDelay: idx * 0.2 + 's' }"
|
|
|
|
|
|
>
|
|
|
|
|
|
<span class="from">{{ map.from }}</span>
|
|
|
|
|
|
<span class="line"></span>
|
|
|
|
|
|
<span class="to">{{ map.to }}</span>
|
|
|
|
|
|
</div>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
</div>
|
2026-02-23 01:40:56 +08:00
|
|
|
|
</div>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
|
2026-02-23 01:40:56 +08:00
|
|
|
|
<!-- 物理内存 -->
|
2026-02-24 00:18:09 +08:00
|
|
|
|
<div class="view-box physical">
|
|
|
|
|
|
<div class="view-title">💾 真实的内存条(物理)</div>
|
|
|
|
|
|
<div class="physical-mem">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="(block, idx) in physicalBlocks"
|
|
|
|
|
|
:key="idx"
|
|
|
|
|
|
class="p-block"
|
|
|
|
|
|
:class="[block.type, { active: block.active }]"
|
2026-02-23 01:40:56 +08:00
|
|
|
|
>
|
2026-02-24 00:18:09 +08:00
|
|
|
|
<span class="p-addr">{{ idx + 1 }}</span>
|
|
|
|
|
|
<span class="p-owner">{{ block.label }}</span>
|
2026-02-18 15:52:55 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-02-23 01:50:43 +08:00
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
<div class="explain">
|
|
|
|
|
|
<strong>💡 原理:</strong>每个程序以为自己独占连续的内存(左),实际上操作系统把数据分散存到真实内存各处(右)。程序看到的地址都是"假"的,操作系统负责翻译。
|
2026-02-18 15:52:55 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2026-02-24 00:18:09 +08:00
|
|
|
|
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
|
|
|
|
|
|
|
|
|
|
|
const wechatProgress = ref(0)
|
|
|
|
|
|
const gameProgress = ref(0)
|
|
|
|
|
|
const currentMapping = ref(0)
|
|
|
|
|
|
|
|
|
|
|
|
// 物理内存状态
|
|
|
|
|
|
const physicalBlocks = ref([
|
|
|
|
|
|
{ type: 'os', label: '系统', active: false },
|
|
|
|
|
|
{ type: 'empty', label: '', active: false },
|
|
|
|
|
|
{ type: 'empty', label: '', active: false },
|
|
|
|
|
|
{ type: 'os', label: '系统', active: false },
|
|
|
|
|
|
{ type: 'empty', label: '', active: false },
|
|
|
|
|
|
{ type: 'empty', label: '', active: false },
|
|
|
|
|
|
{ type: 'empty', label: '', active: false },
|
|
|
|
|
|
{ type: 'os', label: '系统', active: false }
|
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
// 映射关系(虚拟地址 -> 物理地址)
|
|
|
|
|
|
const mappings = [
|
|
|
|
|
|
{ from: '微信-1', to: '物理-2', type: 'wechat' },
|
|
|
|
|
|
{ from: '微信-2', to: '物理-3', type: 'wechat' },
|
|
|
|
|
|
{ from: '游戏-1', to: '物理-5', type: 'game' },
|
|
|
|
|
|
{ from: '游戏-2', to: '物理-6', type: 'game' }
|
2026-02-18 15:52:55 +08:00
|
|
|
|
]
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
const visibleMappings = computed(() => {
|
|
|
|
|
|
return mappings.slice(0, currentMapping.value)
|
2026-02-18 15:52:55 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
let timer = null
|
|
|
|
|
|
let phase = 0
|
|
|
|
|
|
|
|
|
|
|
|
const runDemo = () => {
|
|
|
|
|
|
switch(phase) {
|
|
|
|
|
|
case 0: // 微信申请内存
|
|
|
|
|
|
wechatProgress.value = 50
|
|
|
|
|
|
physicalBlocks.value[1] = { type: 'wechat', label: 'W1', active: true }
|
|
|
|
|
|
physicalBlocks.value[2] = { type: 'wechat', label: 'W2', active: true }
|
|
|
|
|
|
currentMapping.value = 2
|
|
|
|
|
|
phase = 1
|
|
|
|
|
|
break
|
|
|
|
|
|
case 1: // 游戏申请内存
|
|
|
|
|
|
gameProgress.value = 50
|
|
|
|
|
|
physicalBlocks.value[4] = { type: 'game', label: 'G1', active: true }
|
|
|
|
|
|
physicalBlocks.value[5] = { type: 'game', label: 'G2', active: true }
|
|
|
|
|
|
currentMapping.value = 4
|
|
|
|
|
|
phase = 2
|
|
|
|
|
|
break
|
|
|
|
|
|
case 2: // 高亮显示
|
|
|
|
|
|
physicalBlocks.value.forEach(b => b.active = false)
|
|
|
|
|
|
phase = 3
|
|
|
|
|
|
break
|
|
|
|
|
|
case 3: // 重置
|
|
|
|
|
|
wechatProgress.value = 0
|
|
|
|
|
|
gameProgress.value = 0
|
|
|
|
|
|
currentMapping.value = 0
|
|
|
|
|
|
physicalBlocks.value[1] = { type: 'empty', label: '', active: false }
|
|
|
|
|
|
physicalBlocks.value[2] = { type: 'empty', label: '', active: false }
|
|
|
|
|
|
physicalBlocks.value[4] = { type: 'empty', label: '', active: false }
|
|
|
|
|
|
physicalBlocks.value[5] = { type: 'empty', label: '', active: false }
|
|
|
|
|
|
phase = 0
|
|
|
|
|
|
break
|
2026-02-23 01:40:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
timer = setInterval(runDemo, 2000)
|
|
|
|
|
|
})
|
2026-02-23 01:40:56 +08:00
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
onUnmounted(() => {
|
2026-02-26 04:35:28 +08:00
|
|
|
|
if (timer) clearInterval(timer)
|
2026-02-24 00:18:09 +08:00
|
|
|
|
})
|
2026-02-18 15:52:55 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.demo {
|
2026-02-23 01:40:56 +08:00
|
|
|
|
border: 1px solid var(--vp-c-divider);
|
2026-02-24 00:18:09 +08:00
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
background: var(--vp-c-bg-soft);
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
margin: 1rem 0;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.title {
|
2026-02-23 01:40:56 +08:00
|
|
|
|
font-weight: 600;
|
2026-02-24 00:18:09 +08:00
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
text-align: center;
|
2026-02-23 01:40:56 +08:00
|
|
|
|
}
|
2026-02-24 00:18:09 +08:00
|
|
|
|
|
|
|
|
|
|
.scene {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
margin-bottom: 12px;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.view-box {
|
|
|
|
|
|
background: var(--vp-c-bg);
|
2026-02-23 01:40:56 +08:00
|
|
|
|
border: 1px solid var(--vp-c-divider);
|
2026-02-24 00:18:09 +08:00
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
padding: 10px;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
2026-02-24 00:18:09 +08:00
|
|
|
|
|
|
|
|
|
|
.view-box.physical {
|
|
|
|
|
|
background: #1a1a2e11;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.view-title {
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: var(--vp-c-text-3);
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.virtual-mem {
|
2026-02-23 01:40:56 +08:00
|
|
|
|
display: flex;
|
2026-02-24 00:18:09 +08:00
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 8px;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.proc-mem {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.proc-label {
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
width: 50px;
|
|
|
|
|
|
flex-shrink: 0;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.mem-blocks {
|
2026-02-23 01:40:56 +08:00
|
|
|
|
display: flex;
|
2026-02-24 00:18:09 +08:00
|
|
|
|
gap: 4px;
|
|
|
|
|
|
flex: 1;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.v-block {
|
2026-02-18 15:52:55 +08:00
|
|
|
|
flex: 1;
|
2026-02-24 00:18:09 +08:00
|
|
|
|
height: 28px;
|
|
|
|
|
|
border: 1px dashed var(--vp-c-divider);
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
font-size: 10px;
|
|
|
|
|
|
color: var(--vp-c-text-3);
|
|
|
|
|
|
transition: all 0.3s;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.v-block.filled {
|
|
|
|
|
|
background: #16a34a33;
|
|
|
|
|
|
border: 1px solid #16a34a;
|
|
|
|
|
|
color: #16a34a;
|
|
|
|
|
|
font-weight: 600;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.v-block.game.filled {
|
|
|
|
|
|
background: #d9770633;
|
|
|
|
|
|
border-color: #d97706;
|
|
|
|
|
|
color: #d97706;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mapping-arrow {
|
2026-02-23 01:40:56 +08:00
|
|
|
|
text-align: center;
|
2026-02-24 00:18:09 +08:00
|
|
|
|
padding: 4px 0;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.arrow-text {
|
|
|
|
|
|
font-size: 10px;
|
2026-02-23 01:40:56 +08:00
|
|
|
|
color: var(--vp-c-text-3);
|
2026-02-24 00:18:09 +08:00
|
|
|
|
margin-bottom: 4px;
|
2026-02-23 01:40:56 +08:00
|
|
|
|
}
|
2026-02-24 00:18:09 +08:00
|
|
|
|
|
|
|
|
|
|
.mapping-lines {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
flex-wrap: wrap;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.map-line {
|
2026-02-23 01:40:56 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2026-02-24 00:18:09 +08:00
|
|
|
|
gap: 4px;
|
|
|
|
|
|
font-size: 10px;
|
|
|
|
|
|
animation: fade-in 0.3s ease;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.map-line.wechat {
|
|
|
|
|
|
color: #16a34a;
|
2026-02-23 01:40:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.map-line.game {
|
|
|
|
|
|
color: #d97706;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.map-line .line {
|
|
|
|
|
|
width: 20px;
|
|
|
|
|
|
height: 1px;
|
|
|
|
|
|
background: currentColor;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.physical-mem {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(4, 1fr);
|
|
|
|
|
|
gap: 4px;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.p-block {
|
|
|
|
|
|
height: 32px;
|
|
|
|
|
|
border: 1px solid var(--vp-c-divider);
|
|
|
|
|
|
border-radius: 4px;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
2026-02-24 00:18:09 +08:00
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
font-size: 9px;
|
|
|
|
|
|
transition: all 0.3s;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.p-block.os {
|
|
|
|
|
|
background: var(--vp-c-bg-soft);
|
|
|
|
|
|
border-style: dashed;
|
2026-02-23 01:40:56 +08:00
|
|
|
|
color: var(--vp-c-text-3);
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.p-block.wechat {
|
|
|
|
|
|
background: #16a34a22;
|
|
|
|
|
|
border-color: #16a34a;
|
|
|
|
|
|
color: #16a34a;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
2026-02-24 00:18:09 +08:00
|
|
|
|
|
|
|
|
|
|
.p-block.game {
|
|
|
|
|
|
background: #d9770622;
|
|
|
|
|
|
border-color: #d97706;
|
|
|
|
|
|
color: #d97706;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
2026-02-24 00:18:09 +08:00
|
|
|
|
|
|
|
|
|
|
.p-block.active {
|
|
|
|
|
|
box-shadow: 0 0 8px currentColor;
|
|
|
|
|
|
transform: scale(1.05);
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.p-addr {
|
|
|
|
|
|
font-size: 8px;
|
|
|
|
|
|
opacity: 0.7;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.p-owner {
|
|
|
|
|
|
font-weight: 600;
|
2026-02-18 15:52:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 00:18:09 +08:00
|
|
|
|
.explain {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: var(--vp-c-text-2);
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
background: var(--vp-c-bg);
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.explain strong { color: var(--vp-c-text-1); }
|
|
|
|
|
|
|
|
|
|
|
|
@keyframes fade-in {
|
|
|
|
|
|
from { opacity: 0; transform: translateY(-5px); }
|
|
|
|
|
|
to { opacity: 1; transform: translateY(0); }
|
2026-02-23 01:40:56 +08:00
|
|
|
|
}
|
2026-02-18 15:52:55 +08:00
|
|
|
|
</style>
|