You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python动态分区内存分配GUI程序出现IndexError问题求助

动态内存分配模拟程序IndexError排查与修复

问题概述

开发带GUI的Python动态内存分配模拟程序时,触发IndexError: list index out of range错误,报错位置在allocate_memory方法的self.jobs[block_idx] -= process_size行。

报错堆栈

PS C:\Users\Admin> & C:/Users/Admin/AppData/Local/Microsoft/WindowsApps/python3.11.exe "c:/Users/Admin/Downloads/# Simple Python code.py"
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.1776.0_x64__qbz5n2kfra8p0\Lib\tkinter\__init__.py", line 1948, in __call__
    return self.func(*args)
           ^^^^^^^^^^^^^^^^
  File "c:\Users\Admin\Downloads\# Simple Python code.py", line 108, in allocate_memory
    self.memory_simulation.allocate_memory(algorithm)
  File "c:\Users\Admin\Downloads\# Simple Python code.py", line 40, in allocate_memory
    self.jobs[block_idx] -= process_size
    ~~~~~~~~~^^^^^^^^^^^
IndexError: list index out of range

原代码

import tkinter as tk 
from tkinter import ttk

class MemoryAllocationSimulation:
    def __init__(self, memory_size, os_size, initial_jobs):
        self.memory_size = memory_size
        self.os_size = os_size
        self.free_memory = memory_size - os_size
        self.jobs = initial_jobs
        self.allocation = [-1] * (len(initial_jobs) + 10)  # Adjust the size for potential new jobs

    def best_fit(self, process_size):
        best_idx = -1
        for j in range(len(self.jobs) + 1):  # Include free memory as a potential block
            if j == len(self.jobs):  # Check for free memory
                if self.free_memory >= process_size:
                    return j
            elif self.jobs[j] >= process_size:
                if best_idx == -1 or self.jobs[best_idx] > self.jobs[j]:
                    best_idx = j

        return best_idx

    def allocate_memory(self, algorithm):
        # Allocate memory for existing jobs
        for i in range(len(self.jobs)):
            process_size = self.jobs[i]
            if algorithm == "best_fit":
                block_idx = self.best_fit(process_size)
            elif algorithm == "first_fit":
                block_idx = self.first_fit(process_size)
            elif algorithm == "worst_fit":
                block_idx = self.worst_fit(process_size)
            else:
                raise ValueError("Invalid memory allocation algorithm")

            if block_idx != -1:
                self.allocation[i] = block_idx
                self.free_memory -= process_size
                self.jobs[block_idx] -= process_size
            else:
                print(f"Job {i + 1} not allocated due to insufficient memory")

        # Allocate memory for new jobs
        new_jobs = [5, 30]
        for new_job in new_jobs:
            if algorithm == "best_fit":
                block_idx = self.best_fit(new_job)
            elif algorithm == "first_fit":
                block_idx = self.first_fit(new_job)
            elif algorithm == "worst_fit":
                block_idx = self.worst_fit(new_job)
            else:
                raise ValueError("Invalid memory allocation algorithm")

            if block_idx != -1:
                new_job_idx = len(self.jobs) + len(new_jobs) - 2  # Index for new jobs
                self.allocation[new_job_idx] = block_idx
                self.free_memory -= new_job
                self.jobs.append(new_job)  # Append new jobs to the list
                self.jobs[block_idx] -= new_job
            else:
                print(f"New job {new_job} not allocated due to insufficient memory")
                new_job_idx = len(self.jobs) + len(new_jobs) - 2  # Index for new jobs
                self.allocation[new_job_idx] = -1

    def first_fit(self, process_size):
        for j in range(len(self.jobs)):
            if self.jobs[j] >= process_size:
                return j
        return -1

    def worst_fit(self, process_size):
        worst_idx = -1
        for j in range(len(self.jobs)):
            if self.jobs[j] >= process_size:
                if worst_idx == -1 or self.jobs[worst_idx] < self.jobs[j]:
                    worst_idx = j
        return worst_idx 

class MemoryAllocationGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("Memory Allocation Simulation")

        self.memory_simulation = MemoryAllocationSimulation(100, 5, [15, 20])

        self.algorithm_label = ttk.Label(root, text="Select Allocation Algorithm:")
        self.algorithm_label.pack(pady=10)

        self.algorithm_var = tk.StringVar()
        self.algorithm_var.set("best_fit")

        self.algorithm_combobox = ttk.Combobox(root, textvariable=self.algorithm_var, values=["best_fit", "first_fit", "worst_fit"])
        self.algorithm_combobox.pack(pady=10)

        self.allocate_button = ttk.Button(root, text="Allocate Memory", command=self.allocate_memory)
        self.allocate_button.pack(pady=10)

        self.tree = ttk.Treeview(root, columns=('Job', 'Size', 'Block'))
        self.tree.heading('#0', text='Process No.')
        self.tree.heading('Job', text='Process Size')
        self.tree.heading('Size', text='Block No.')
        self.tree.pack(pady=10)

    def allocate_memory(self):
        algorithm = self.algorithm_var.get()
        self.memory_simulation.allocate_memory(algorithm)
        self.display_memory_status()

    def display_memory_status(self):
        self.tree.delete(*self.tree.get_children())
        for i in range(len(self.memory_simulation.jobs)):
            process_size = self.memory_simulation.jobs[i]
            block_no = self.memory_simulation.allocation[i] + 1 if self.memory_simulation.allocation[i] != -1 else "Not Allocated"
            self.tree.insert('', i, text=f'Job {i + 1}', values=(process_size, block_no))

        free_memory = self.memory_simulation.free_memory
        self.tree.insert('', len(self.memory_simulation.jobs), text='Free Memory', values=(free_memory, ''))

if __name__ == "__main__":
    root = tk.Tk()
    gui = MemoryAllocationGUI(root)
    root.mainloop()

错误原因分析

  1. 索引超出范围:best_fit方法中,当j == len(self.jobs)时直接返回该索引,而self.jobs的最大有效索引是len(self.jobs)-1,后续操作self.jobs[block_idx]必然触发越界。
  2. 逻辑混淆:原代码将待分配作业和内存块合并在jobs列表中,导致分配逻辑混乱,新作业索引计算错误(new_job_idx = len(self.jobs) + len(new_jobs) - 2)。
  3. 空闲内存处理错误:使用空闲内存分配时,未将空闲内存转换为实际内存块,直接操作无效索引。

修复后代码

import tkinter as tk 
from tkinter import ttk

class MemoryAllocationSimulation:
    def __init__(self, memory_size, os_size, initial_jobs):
        self.memory_size = memory_size
        self.os_size = os_size
        # 内存块列表:初始为空闲块,待分配作业单独存储
        self.memory_blocks = [memory_size - os_size - sum(initial_jobs)]
        self.jobs_to_allocate = initial_jobs.copy()
        self.allocation = [-1] * (len(initial_jobs) + 10)  # 预留新作业空间

    def best_fit(self, process_size):
        best_idx = -1
        for j in range(len(self.memory_blocks)):
            if self.memory_blocks[j] >= process_size:
                if best_idx == -1 or self.memory_blocks[best_idx] > self.memory_blocks[j]:
                    best_idx = j
        return best_idx

    def allocate_memory(self, algorithm):
        # 添加新作业
        self.jobs_to_allocate.extend([5, 30])
        # 遍历所有待分配作业
        for idx, process_size in enumerate(self.jobs_to_allocate):
            if algorithm == "best_fit":
                block_idx = self.best_fit(process_size)
            elif algorithm == "first_fit":
                block_idx = self.first_fit(process_size)
            elif algorithm == "worst_fit":
                block_idx = self.worst_fit(process_size)
            else:
                raise ValueError("Invalid memory allocation algorithm")

            if block_idx != -1:
                self.allocation[idx] = block_idx
                # 分配内存:减少块大小,剩余为0则删除该块
                self.memory_blocks[block_idx] -= process_size
                if self.memory_blocks[block_idx] == 0:
                    del self.memory_blocks[block_idx]
                    # 更新后续作业的块索引
                    for i in range(idx + 1, len(self.allocation)):
                        if self.allocation[i] > block_idx:
                            self.allocation[i] -= 1
            else:
                print(f"Job {idx + 1} ({process_size} units) not allocated due to insufficient memory")

    def first_fit(self, process_size):
        for j in range(len(self.memory_blocks)):
            if self.memory_blocks[j] >= process_size:
                return j
        return -1

    def worst_fit(self, process_size):
        worst_idx = -1
        for j in range(len(self.memory_blocks)):
            if self.memory_blocks[j] >= process_size:
                if worst_idx == -1 or self.memory_blocks[worst_idx] < self.memory_blocks[j]:
                    worst_idx = j
        return worst_idx 

class MemoryAllocationGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("Memory Allocation Simulation")

        # 初始化:内存总100,OS占5,初始待分配作业[15,20],初始空闲内存60
        self.memory_simulation = MemoryAllocationSimulation(100, 5, [15, 20])

        self.algorithm_label = ttk.Label(root, text="选择分配算法:")
        self.algorithm_label.pack(pady=10)

        self.algorithm_var = tk.StringVar()
        self.algorithm_var.set("best_fit")

        self.algorithm_combobox = ttk.Combobox(root, textvariable=self.algorithm_var, values=["best_fit", "first_fit", "worst_fit"])
        self.algorithm_combobox.pack(pady=10)

        self.allocate_button = ttk.Button(root, text="分配内存", command=self.allocate_memory)
        self.allocate_button.pack(pady=10)

        # 作业分配状态视图
        self.job_tree = ttk.Treeview(root, columns=('JobSize', 'BlockIndex'))
        self.job_tree.heading('#0', text='作业编号')
        self.job_tree.heading('JobSize', text='作业大小')
        self.job_tree.heading('BlockIndex', text='分配块索引')
        self.job_tree.pack(pady=10)

        # 内存块状态视图
        self.block_tree = ttk.Treeview(root, columns=('BlockSize', 'Status'))
        self.block_tree.heading('#0', text='内存块编号')
        self.block_tree.heading('BlockSize', text='块大小')
        self.block_tree.heading('Status', text='状态')
        self.block_tree.pack(pady=10)

    def allocate_memory(self):
        algorithm = self.algorithm_var.get()
        # 重置模拟状态,避免重复分配
        self.memory_simulation = MemoryAllocationSimulation(100, 5, [15, 20])
        self.memory_simulation.allocate_memory(algorithm)
        self.display_memory_status()

    def display_memory_status(self):
        # 清空视图
        self.job_tree.delete(*self.job_tree.get_children())
        self.block_tree.delete(*self.block_tree.get_children())

        # 显示作业分配状态
        for idx, job_size in enumerate(self.memory_simulation.jobs_to_allocate):
            block_idx = self.memory_simulation.allocation[idx]
            block_text = str(block_idx + 1) if block_idx != -1 else "未分配"
            self.job_tree.insert('', idx, text=f'作业 {idx + 1}', values=(job_size, block_text))

        # 显示内存块状态
        for idx, block_size in enumerate(self.memory_simulation.memory_blocks):
            self.block_tree.insert('', idx, text=f'块 {idx + 1}', values=(block_size, '空闲'))

if __name__ == "__main__":
    root = tk.Tk()
    gui = MemoryAllocationGUI(root)
    root.mainloop()

关键修正说明

  1. 分离作业与内存块:将待分配作业和内存块分开存储,避免逻辑混淆,从根源解决索引越界问题。
  2. 修复空闲内存处理:空闲内存作为独立内存块存在,分配后自动调整块大小或删除空块,同时更新后续作业的块索引。
  3. 重置模拟状态:每次分配前重置模拟实例,避免重复分配导致的逻辑错误。
  4. 优化GUI显示:新增内存块状态视图,更直观展示内存分配结果。

内容的提问来源于stack exchange,提问作者newbie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 08:55:54