页面置换算法问题请教

第一个问题:Unboxing of 'fifoQueue.peek()' may produce 'NullPointerException'
第二个问题:Cannot resolve symbol 'pageLastUsed'
源代码
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;

public class PageReplacementExperiment {

public static void main(String[] args) {
    // 页面访问顺序
    int[] pageList = {3, 4, 2, 8, 1, 2, 3, 3, 4, 2, 3, 4, 6, 1, 5, 4, 2, 3, 7, 8, 4, 8, 7, 3, 4, 7, 8, 5, 4, 5, 3, 4, 3, 7, 8, 4, 5, 1, 2, 1};
    // 内存块数
    int numMemoryBlocks = 4;

    // 执行 OPT 算法
    int[] optFaultSequence = opt(pageList, numMemoryBlocks);
    double optPageFaultRate = getPageFaultRate(optFaultSequence, pageList.length);
    System.out.println("OPT 算法:");
    System.out.println("缺页率:" + optPageFaultRate);
    System.out.println("缺页序列:" + Arrays.toString(optFaultSequence));

    // 执行 FIFO 算法
    int[] fifoFaultSequence = fifo(pageList, numMemoryBlocks);
    double fifoPageFaultRate = getPageFaultRate(fifoFaultSequence, pageList.length);
    System.out.println("FIFO 算法:");
    System.out.println("缺页率:" + fifoPageFaultRate);
    System.out.println("缺页序列:" + Arrays.toString(fifoFaultSequence));

    // 执行 LRU 算法
    int[] lruFaultSequence = lru(pageList, numMemoryBlocks);
    double lruPageFaultRate = getPageFaultRate(lruFaultSequence, pageList.length);
    System.out.println("LRU 算法:");
    System.out.println("缺页率:" + lruPageFaultRate);
    System.out.println("缺页序列:" + Arrays.toString(lruFaultSequence));
}

/**
 * OPT 算法
 */
public static int[] opt(int[] pageList, int numMemoryBlocks) {
    int[] faultSequence = new int[pageList.length];
    int[] memoryBlocks = new int[numMemoryBlocks];
    ArrayList<Integer> pageListRemaining = new ArrayList<>();
    for (int i = 0; i < pageList.length; i++) {
        pageListRemaining.add(pageList[i]);
    }

    for (int i = 0; i < pageList.length; i++) {
        int page = pageList[i];
        boolean pageInMemory = false;

        // 判断页面是否在内存块数组中
  for (int j = 0; j < numMemoryBlocks; j++) {
            if (memoryBlocks[j] == page) {
                pageInMemory = true;
                break;
            }
        }

        if (!pageInMemory) {
            // 如果页面不在内存块数组中,则进行页面置换
            faultSequence[i] = page;
            int[] memoryBlocksNext = new int[numMemoryBlocks];
            for (int j = 0; j < numMemoryBlocks; j++) {
                // 如果内存块未被使用,则直接将页面加入内存块
                if (memoryBlocks[j] == 0) {
                    memoryBlocksNext[j] = page;
                    break;
                } else {
                    // 如果内存块已被使用,则查找下一次使用该页面的位置
                    boolean pageFound = false;
                    for (int k = i + 1; k < pageList.length; k++) {
                        if (memoryBlocks[j] == pageList[k]) {
                            memoryBlocksNext[j] = memoryBlocks[j];
                            pageFound = true;
                            break;
                        }
                    }
                    if (!pageFound) {
                        memoryBlocksNext[j] = page;
                        break;
                    }
                }
            }
            memoryBlocks = memoryBlocksNext;
        }
    }

    return faultSequence;
}

/**
 * FIFO 算法
 */
public static int[] fifo(int[] pageList, int numMemoryBlocks) {
    int[] faultSequence = new int[pageList.length];
    int[] memoryBlocks = new int[numMemoryBlocks];
    Queue<Integer> fifoQueue = new LinkedList<>();

    for (int i = 0; i < pageList.length; i++) {
        int page = pageList[i];
        boolean pageInMemory = false;

        // 判断页面是否在内存块数组中
        for (int j = 0; j < numMemoryBlocks; j++) {
            if (memoryBlocks[j] == page) {
                pageInMemory = true;
                break;
            }
        }

        if (!pageInMemory) {
        // 如果页面不在内存块数组中,则进行页面置换
        faultSequence[i] = page;
        int memoryBlockIndex = -1;
        for (int j = 0; j < numMemoryBlocks; j++) {
            // 如果内存块未被使用,则直接将页面加入内存块
            if (memoryBlocks[j] == 0) {
                memoryBlockIndex = j;
                break;
            } else {
                // 如果内存块已被使用,则查找 FIFO 队列中的页面
                if (fifoQueue.peek() == memoryBlocks[j]) {
                    memoryBlockIndex = j;
                    break;
                }
            }
        }
        fifoQueue.add(page);
        if (memoryBlockIndex != -1) {
            memoryBlocks[memoryBlockIndex] = page;
            fifoQueue.poll();
        }
    }
}

return faultSequence;

}

/**

  • LRU 算法

  • /
    public static int[] lru(int[] pageList, int numMemoryBlocks) {
    int[] faultSequence = new int[pageList.length];
    int[] memoryBlocks = new int[numMemoryBlocks];
    ArrayList pageListRemaining = new ArrayList<>();
    for (int i = 0; i < pageList.length; i++) {

      pageListRemaining.add(pageList[i]);
    

    }

    for (int i = 0; i < pageList.length; i++) {

      int page = pageList[i];
      boolean pageInMemory = false;
    
      // 判断页面是否在内存块数组中
      for (int j = 0; j < numMemoryBlocks; j++) {
          if (memoryBlocks[j] == page) {
              pageInMemory = true;
              break;
          }
      }
    
      if (!pageInMemory) {
          // 如果页面不在内存块数组中,则进行页面置换
          faultSequence[i] = page;
          int[] memoryBlocksNext = new int[numMemoryBlocks];
          int[] pageLastUsed = new int[numMemoryBlocks];
          for (int j = 0; j < numMemoryBlocks; j++) {
              // 如果内存块未被使用,则直接将页面加入内存块
              if (memoryBlocks[j] == 0) {
                  memoryBlocksNext[j] = page;
                  pageLastUsed[j] = i;
                  break;
              } else {
                  // 如果内存块已被使用,则查找最近最久未使用的页面
                  int lruIndex = -1;
                  int lruTime = Integer.MAX_VALUE;
                  for (int k = 0; k < numMemoryBlocks; k++) {
                      int timeSinceLastUse = i - pageLastUsed[k];
                      if (timeSinceLastUse > 0 && timeSinceLastUse < lruTime) {
                          lruIndex = k;
                          lruTime = timeSinceLastUse;
                      }
                  }
                  if (lruIndex != -1) {
                      memoryBlocksNext[lruIndex] = page;
                      pageLastUsed[lruIndex] = i;
                      break;
                  }
              }
          }
          memoryBlocks = memoryBlocksNext;
      } else {
          // 如果页面已经在内存块数组中,则更新该页面的最近使用时间
          for (int j = 0; j < numMemoryBlocks; j++) {
              if (memoryBlocks[j] == page) {
                  pageLastUsed[j] = i;
                  break;
              }
          }
      }
    

    }

    return faultSequence;
    }
    /**

  • 计算缺页率

  • /
    public static double getPageFaultRate(int[] faultSequence, int numPages) {
    int numFaults = 0;
    for (int i = 0; i < faultSequence.length; i++) {

      if (faultSequence[i] != 0) {
          numFaults++;
      }
    

    }
    return (double) numFaults / numPages;
    }


第一个问题:Unboxing of 'fifoQueue.peek()' may produce 'NullPointerException'
解决方法:在调用fifoQueue.peek()前检查fifoQueue是否为空,如果为空则不调用peek()方法。可以这样修改:
java
if (!fifoQueue.isEmpty()) {
    if (fifoQueue.peek() == memoryBlocks[j]) {
        // ...
    } 
}
第二个问题:Cannot resolve symbol 'pageLastUsed'
解决方法:在LRU算法中,pageLastUsed数组是新定义的,所以需要先声明它,可以在int[] memoryBlocksNext = new int[numMemoryBlocks];前面添加:
java 
int[] pageLastUsed = new int[numMemoryBlocks];
所以完整的LRU算法可以修改为:
java
public static int[] lru(int[] pageList, int numMemoryBlocks) {
    int[] faultSequence = new int[pageList.length];
    int[] memoryBlocks = new int[numMemoryBlocks];
    int[] pageLastUsed = new int[numMemoryBlocks]; // 添加这行
    ArrayList pageListRemaining = new ArrayList<>();
    // ...
}
希望这能帮助您解决问题!
不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 以下回答来自chatgpt:

    答案: 1. 这个提示意味着fifoQueue.peek()方法返回的结果可能为null,如果在之后的操作中尝试把它当做正常的对象使用,会导致NullPointerException异常。因此,我们需要在使用之前进行判空处理。可以使用类似下面的代码:

    Page currentPage = fifoQueue.peek();
    if(currentPage != null){
        // currentPage进行操作
    }
    

    这里,我们首先获取peek()方法返回的currentPage对象,然后检查它是否为null。如果不为空,就执行我们需要进行的操作。

    1. “Cannot resolve symbol 'pageLastUsed'”的提示表示pageLastUsed变量未被声明,或者已经超出了它的作用域。首先,我们需要确认该变量是否已正确声明。如果已经声明,那么我们需要检查它的作用域,确保它在需要使用的地方是可见的。如果它的作用域是局部变量,那么它只能在声明它的代码块中使用。如果它的作用域是全局变量,那么在代码的任何地方都可以使用它。我们需要根据实际情况进行判断和调整。

    2. 缺页率是指发生缺页的次数与总访问次数的比值。在页面置换算法中,我们可以在访问每个页面时计算缺页率。具体步骤如下:

    3. 声明两个变量:pageNum和missNum,分别表示访问的页面总数和发生缺页的页面数。

    4. 在访问每一个页面时,pageNum加1。
    5. 如果当前页面不在内存中,missNum加1,并将该页面加入内存。
    6. 计算缺页率missRate = missNum / pageNum。注意:在实际应用中,我们可能需要将该比率乘以100,并进行格式化输出。

    这里是一个示例代码片段:

    int pageNum = 0;
    int missNum = 0;
    for(int i = 0; i < pageReferences.length; i++){
        int page = pageReferences[i];
        pageNum++;
        if(!memory.contains(page)){ // 内存中没有该页面
            missNum++;
            if(memory.size() == memoryCapacity){ // 内存已满需要进行置换
                int replacedPage = replacePage(page); // 选择要置换的页面
                memory.remove(replacedPage); // 从内存中移除被置换的页面
            }
            memory.add(page); // 将新页面加入内存
        }
    }
    double missRate = (double)missNum / pageNum;
    System.out.format("缺页率为:%.2f%%", missRate * 100);
    

    在这个例子中,我们使用了一个名为memory的Set集合来存储当前已经在内存中的页面,同时使用了一个名为replacePage()的方法来确定要置换的页面。根据实际情况,我们可能需要进行适当的调整。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^