实验五 虚拟内存页面置换算法
2015-12-30 16:45
246 查看
一、 需求分析
说明程序设计的任务和目的,明确规定下述内容:
加深对虚拟内存页面置换概念的理解,进一步掌握先进先出FIFO、最佳置换OPI和最近最久未使用LRU页面置换算法的实现方法。
(1) 输入的形式和输入值的范围;
输入1-3的整数选择算法
已在程序中预置好页面信息和页面访问顺序
(2) 输出的形式;
页面置换的过程和置换后内存的状态
(3) 程序所能达到的功能;
模拟先出FIFO、最佳置换OPI和最近最久未使用LRU页面置换算法
(4) 测试数据,包括正确的输入及其输出结果和含有错误的输入及其输出结果。
依次输入1 2 3选择相应算法
输出置换过程
二、 概要设计
说明本程序中用到的所有抽象数据类型的定义、主程序的流程以及各程序模块之间的层次(调用)关系。
页面文件对象
classPage
{
publicstring id;//页面文件id
publicstring name;//页面文件名称
publicint timeInRAM;//页面文件在内存中的
时间
publicint comeInTime;//页面文件在内存中的
进入内存的时间
publicintlatestVisitTimeInPast;//页面文件在内存中的最近的访问时间
publicint timeSpanToVisit;//该页面在将来第一次访问
到现在的时间间隔
publicint visitCount;
//页面文件在内存中的访问次数
}
内存对象
classRAM
{
publicint breakCount;//中断次数
publicint size;//内存可存放页面文件的总个数
publicint freeSize;//空闲个数
publicint freePostion;//置换过程中临时留下的空位索引[默认-2,无空位时为-1]
publicList<Page>
RAMDetail;//内存中页面文件的状态
}
三、 详细设计
实现程序模块的具体算法。
publicPage GetPageofLongest()
publicPage GetPageofRecentUnused(
string[] orders,int currentOrderIndex)
publicPage GetPageofLastUseInfutrue(string[]
orders ,int currentOrderIndex)
四、 调试分析
(1) 调试过程中遇到的问题以及解决方法,设计与实现的回顾讨论和分析;
开始时对最近最久未使用算法理解不清楚,导致运行结果正确。以后在编写程序前应对算法充分理解在进行编程,防止时间浪费
五、 用户使用说明
程序的使用说明,列出每一步的操作步骤。
运行程序--选择算法--查看结果
六、 测试结果
列出测试结果,包括输入和输出。
![](https://img-blog.csdn.net/20151230164451005?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](https://img-blog.csdn.net/20151230164501656?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](https://img-blog.csdn.net/20151230164518534?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lab5
{
//页面文件
class Page
{
public string id;//页面文件id
public string name;//页面文件名称
public int timeInRAM;//页面文件在内存中的 时间
public int comeInTime;//页面文件在内存中的 进入内存的时间
public int latestVisitTimeInPast;//页面文件在内存中的 最近的访问时间
public int timeSpanToVisit;//该页面在将来第一次访问 到现在的时间间隔
public int visitCount; //页面文件在内存中的 访问次数
public Page(string id, string name)
{
this.id = id;
this.name = name;
timeInRAM = 0;
visitCount = 0;
comeInTime = -1;
latestVisitTimeInPast = int.MinValue;
timeSpanToVisit = int.MaxValue;
}
//页面文件进入内存
public void ComeInRAM(int time)
{
comeInTime = time;
latestVisitTimeInPast = comeInTime;
timeInRAM++;
VistInRAM(time);//进入时访问次数增加
}
//页面文件停留在内存中
public void StayInRAM()
{
timeInRAM++;
}
//页面文件被移出内存
public void GoOutRAM()
{
comeInTime = -1;
timeInRAM=0;
visitCount = 0;
}
//在内存中被访问
public void VistInRAM(int time)
{
latestVisitTimeInPast = comeInTime;
visitCount++;
}
public void Print()
{
Console.Write(name ); //Console.Write(name + "[" + id + "]");
}
}
class RAM
{
public int breakCount;//中断次数
public int size;//内存可存放页面文件的总个数
public int freeSize;//空闲个数
public int freePostion;//置换过程中临时留下的空位索引[默认-2,无空位时为-1]
public List<Page> RAMDetail;//内存中页面文件的状态
public RAM(int size)
{
this.size = size;
freeSize = size;
RAMDetail = new List<Page>();
freePostion = -2;
breakCount = 0;
}
public void PrintPageState()
{
if (size != RAMDetail.Count+freeSize)
{
Console.WriteLine("数据有误");
return;
}
for (int i = 0; i < RAMDetail.Count; i++)
{
RAMDetail[i].Print();
}
}
//新进入页面文件
public void ComeIn(Page page,int time)
{
page.ComeInRAM(time);
if( freePostion == -2)
{
RAMDetail.Add(page);
}
else
{
RAMDetail.Insert(freePostion,page);
}
freeSize--;
if(freeSize==0)
{
freePostion = -1;
}
Console.WriteLine("\n---正在将[" + page.name + "]装入内存...\n");
}
//丢弃页面文件
public void GoOut(Page page)
{
page.GoOutRAM();
freePostion = GetIndexById(page.id);//找到位置
RAMDetail.RemoveAt(freePostion);
freeSize++;
Console.WriteLine("\n---正在将[" + page.name + "]移出内存...\n");
}
//不置换页面时调用
public void FinishChage()
{
for (int k = 0; k < RAMDetail.Count; k++)
{
RAMDetail[k].StayInRAM();
}
PrintPageState(); Console.WriteLine("");
}
public bool IsInRAM(Page page)
{
return (from t in RAMDetail
where t.id == page.id
select t).FirstOrDefault() == null ? false : true;
}
//1-【FIFO】先进先出 获取最先进入的(在内存中待的时间最长)
public Page GetPageofLongest()
{
int maxValue = 0;
int maxIndex = 0;
for (int i = 0; i < RAMDetail.Count; i++)
{
if (RAMDetail[i].timeInRAM > maxValue)
{
maxIndex = i;
maxValue = RAMDetail[i].timeInRAM;
}
}
return RAMDetail[maxIndex];
}
//2-【LRU】最近最久 //往当前序列向前看 n-1个,如果内存中的页面文件出现了,则从缓存中移出,若均未出现,则找出最先进入的返回
public Page GetPageofRecentUnused( string[] orders,int currentOrderIndex)
{
//创建缓存
List<Page> temp = new List<Page>(RAMDetail);
//查找历史访问
int start = currentOrderIndex - 1;
int end=start - (size - 1)+1;
for (int i = start; i >= end; i--)
{
//判断该页是否在内存中
int index=GetIndexById(orders[i]);
//如果在内存中
if (index != -1)
{//从缓存中删除
temp.Remove(Tool.GetPageById(RAMDetail, orders[i]));
}
}
//缓存中剩余数量大于1
return temp.Count > 1 ? Tool.GetPageofLongest(temp) : temp[0];
}
//3-【OPT】最佳 根据请求序列找出 最后使用的那个移出
public Page GetPageofLastUseInfutrue(string[] orders ,int currentOrderIndex)
{
//将来再也不会被请求的页面集合
List<Page> dontShowPageList = new List<Page>();
int start = currentOrderIndex + 1;
int end = orders.Length-1;
for (int i = 0; i < RAMDetail.Count;i++ )
{
bool pageWiilUse = false;
Page currentPage=RAMDetail[i];
//该页面在将来第一次访问 到现在的时间间隔
int timeSpanToVisit = 1;
for (int j = start; j < end; j++)
{
//计算间隔
if(currentPage.id==orders[j])
{
currentPage.timeSpanToVisit = timeSpanToVisit;
break;
}
else
{
timeSpanToVisit++;
}
}
//遍历完序列都没找到,加入集合
if (timeSpanToVisit == end-start+1)
dontShowPageList.Add(currentPage);
}
//如果不需要的少于1个
if (dontShowPageList.Count <=1 )
{
//找出最timeSpanToVisit最大的返回
int maxValue =int.MaxValue;
int maxIndex = -1;
for (int i = 0; i < RAMDetail.Count; i++)
{
if (RAMDetail[i].timeSpanToVisit >= maxValue)
{
maxValue = RAMDetail[i].timeSpanToVisit;
maxIndex = i;
}
}
return RAMDetail[maxIndex];
}
else
{//否则在不需要中找到待的最久的
return Tool.GetPageofLongest(dontShowPageList);
}
}
//获取最先进入的(在内存中待的时间最长)
public int GetIndexById(string id)
{
for (int i = 0; i < RAMDetail.Count; i++)
{
if (RAMDetail[i].id == id)
{
return i;
}
}
return -1;
}
public void processPage(List<Page> pageList, string[] orders,string flag="1")
{
Console.Write(" \n运行过程如下: \n");
//计时器
int time = 0;
//按id顺序访问页面
for (int i = 0; i < orders.Length; i++)
{
Console.WriteLine("\n------------------正在请求[" + Tool.GetPageById(pageList, orders[i]).name + "]... \n");
time++;
Page currentPage = Tool.GetPageById(pageList, orders[i]);
//有空位
if (freeSize > 0)
{
//新来的进入
ComeIn(currentPage, time);
//结束置换
FinishChage();
}
else
{//没空位
//如果没在RAM中,置换页面并产生中断
if (!IsInRAM(currentPage))
{
//中断
breakCount++;
switch (flag)
{
case "1":
{
//1先进先出(在内存中待的时间最长的先出去)
GoOut(GetPageofLongest());
}
break;
case "2":
{
//2最近最久未使用
GoOut(GetPageofRecentUnused(orders, i));
}
break;
case "3":
{
//3最优
GoOut(GetPageofLastUseInfutrue(orders, i));
}
break;
default: Console.WriteLine("输入有误,程序即将终止!"); break;
}
//新来的进入
ComeIn(currentPage, time);
//结束置换
FinishChage();
}
else
{//如果在RAM中,不置换,全都待在内存中
currentPage.VistInRAM(time);
FinishChage();
}
}
}
}
}
class Tool
{
public static Page GetPageById(List<Page> pageList,string id)
{
return pageList.Where(m => m.id == id).FirstOrDefault();
}
public static void PrintPageList(List<Page> pageList)
{
Console.Write(" \n页面文件如下: \n");
for (int i = 0; i < pageList.Count; i++)
{
pageList[i].Print(); Console.Write(" ");
}
Console.Write("\n");
}
public static void PrintOrders(string[] orders)
{
Console.Write(" \n页面访问顺序[页面ID]如下: \n");
for (int i = 0; i < orders.Length; i++)
{
Console.Write(orders[i]+" ");
}
Console.Write("\n");
}
public static Page GetPageofLongest(List<Page> pageList)
{
int maxValue = 0;
int maxIndex = 0;
for (int i = 0; i < pageList.Count; i++)
{
if (pageList[i].timeInRAM > maxValue)
{
maxIndex = i;
maxValue = pageList[i].timeInRAM;
}
}
return pageList[maxIndex];
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("----------虚拟内存页面置换算法----------- ");
List<Page> pageList = new List<Page>();
pageList.Add(new Page("0", "页面0"));
pageList.Add(new Page("1","页面1"));
pageList.Add(new Page("2", "页面2"));
pageList.Add(new Page("3", "页面3"));
pageList.Add(new Page("4", "页面4"));
pageList.Add(new Page("5", "页面5"));
pageList.Add(new Page("6", "页面6"));
string[] orders = new string[] { "6", "0", "1", "2", "0", "3", "0", "4", "2", "3" };
Tool.PrintPageList(pageList);
Tool.PrintOrders(orders);
RAM ram = new RAM(3);
Console.Write(" \n选择算法: 1-【FIFO】先进先出 2-【LRU】最近最久 3-【OPT】最佳 \n");
ram.processPage(pageList, orders,Console.ReadLine());
Console.ReadLine();
}
}
}
七、 附录
带注释的源程序,注释应清楚具体;
说明程序设计的任务和目的,明确规定下述内容:
加深对虚拟内存页面置换概念的理解,进一步掌握先进先出FIFO、最佳置换OPI和最近最久未使用LRU页面置换算法的实现方法。
(1) 输入的形式和输入值的范围;
输入1-3的整数选择算法
已在程序中预置好页面信息和页面访问顺序
(2) 输出的形式;
页面置换的过程和置换后内存的状态
(3) 程序所能达到的功能;
模拟先出FIFO、最佳置换OPI和最近最久未使用LRU页面置换算法
(4) 测试数据,包括正确的输入及其输出结果和含有错误的输入及其输出结果。
依次输入1 2 3选择相应算法
输出置换过程
二、 概要设计
说明本程序中用到的所有抽象数据类型的定义、主程序的流程以及各程序模块之间的层次(调用)关系。
页面文件对象
classPage
{
publicstring id;//页面文件id
publicstring name;//页面文件名称
publicint timeInRAM;//页面文件在内存中的
时间
publicint comeInTime;//页面文件在内存中的
进入内存的时间
publicintlatestVisitTimeInPast;//页面文件在内存中的最近的访问时间
publicint timeSpanToVisit;//该页面在将来第一次访问
到现在的时间间隔
publicint visitCount;
//页面文件在内存中的访问次数
}
内存对象
classRAM
{
publicint breakCount;//中断次数
publicint size;//内存可存放页面文件的总个数
publicint freeSize;//空闲个数
publicint freePostion;//置换过程中临时留下的空位索引[默认-2,无空位时为-1]
publicList<Page>
RAMDetail;//内存中页面文件的状态
}
三、 详细设计
实现程序模块的具体算法。
publicPage GetPageofLongest()
publicPage GetPageofRecentUnused(
string[] orders,int currentOrderIndex)
publicPage GetPageofLastUseInfutrue(string[]
orders ,int currentOrderIndex)
四、 调试分析
(1) 调试过程中遇到的问题以及解决方法,设计与实现的回顾讨论和分析;
开始时对最近最久未使用算法理解不清楚,导致运行结果正确。以后在编写程序前应对算法充分理解在进行编程,防止时间浪费
五、 用户使用说明
程序的使用说明,列出每一步的操作步骤。
运行程序--选择算法--查看结果
六、 测试结果
列出测试结果,包括输入和输出。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lab5
{
//页面文件
class Page
{
public string id;//页面文件id
public string name;//页面文件名称
public int timeInRAM;//页面文件在内存中的 时间
public int comeInTime;//页面文件在内存中的 进入内存的时间
public int latestVisitTimeInPast;//页面文件在内存中的 最近的访问时间
public int timeSpanToVisit;//该页面在将来第一次访问 到现在的时间间隔
public int visitCount; //页面文件在内存中的 访问次数
public Page(string id, string name)
{
this.id = id;
this.name = name;
timeInRAM = 0;
visitCount = 0;
comeInTime = -1;
latestVisitTimeInPast = int.MinValue;
timeSpanToVisit = int.MaxValue;
}
//页面文件进入内存
public void ComeInRAM(int time)
{
comeInTime = time;
latestVisitTimeInPast = comeInTime;
timeInRAM++;
VistInRAM(time);//进入时访问次数增加
}
//页面文件停留在内存中
public void StayInRAM()
{
timeInRAM++;
}
//页面文件被移出内存
public void GoOutRAM()
{
comeInTime = -1;
timeInRAM=0;
visitCount = 0;
}
//在内存中被访问
public void VistInRAM(int time)
{
latestVisitTimeInPast = comeInTime;
visitCount++;
}
public void Print()
{
Console.Write(name ); //Console.Write(name + "[" + id + "]");
}
}
class RAM
{
public int breakCount;//中断次数
public int size;//内存可存放页面文件的总个数
public int freeSize;//空闲个数
public int freePostion;//置换过程中临时留下的空位索引[默认-2,无空位时为-1]
public List<Page> RAMDetail;//内存中页面文件的状态
public RAM(int size)
{
this.size = size;
freeSize = size;
RAMDetail = new List<Page>();
freePostion = -2;
breakCount = 0;
}
public void PrintPageState()
{
if (size != RAMDetail.Count+freeSize)
{
Console.WriteLine("数据有误");
return;
}
for (int i = 0; i < RAMDetail.Count; i++)
{
RAMDetail[i].Print();
}
}
//新进入页面文件
public void ComeIn(Page page,int time)
{
page.ComeInRAM(time);
if( freePostion == -2)
{
RAMDetail.Add(page);
}
else
{
RAMDetail.Insert(freePostion,page);
}
freeSize--;
if(freeSize==0)
{
freePostion = -1;
}
Console.WriteLine("\n---正在将[" + page.name + "]装入内存...\n");
}
//丢弃页面文件
public void GoOut(Page page)
{
page.GoOutRAM();
freePostion = GetIndexById(page.id);//找到位置
RAMDetail.RemoveAt(freePostion);
freeSize++;
Console.WriteLine("\n---正在将[" + page.name + "]移出内存...\n");
}
//不置换页面时调用
public void FinishChage()
{
for (int k = 0; k < RAMDetail.Count; k++)
{
RAMDetail[k].StayInRAM();
}
PrintPageState(); Console.WriteLine("");
}
public bool IsInRAM(Page page)
{
return (from t in RAMDetail
where t.id == page.id
select t).FirstOrDefault() == null ? false : true;
}
//1-【FIFO】先进先出 获取最先进入的(在内存中待的时间最长)
public Page GetPageofLongest()
{
int maxValue = 0;
int maxIndex = 0;
for (int i = 0; i < RAMDetail.Count; i++)
{
if (RAMDetail[i].timeInRAM > maxValue)
{
maxIndex = i;
maxValue = RAMDetail[i].timeInRAM;
}
}
return RAMDetail[maxIndex];
}
//2-【LRU】最近最久 //往当前序列向前看 n-1个,如果内存中的页面文件出现了,则从缓存中移出,若均未出现,则找出最先进入的返回
public Page GetPageofRecentUnused( string[] orders,int currentOrderIndex)
{
//创建缓存
List<Page> temp = new List<Page>(RAMDetail);
//查找历史访问
int start = currentOrderIndex - 1;
int end=start - (size - 1)+1;
for (int i = start; i >= end; i--)
{
//判断该页是否在内存中
int index=GetIndexById(orders[i]);
//如果在内存中
if (index != -1)
{//从缓存中删除
temp.Remove(Tool.GetPageById(RAMDetail, orders[i]));
}
}
//缓存中剩余数量大于1
return temp.Count > 1 ? Tool.GetPageofLongest(temp) : temp[0];
}
//3-【OPT】最佳 根据请求序列找出 最后使用的那个移出
public Page GetPageofLastUseInfutrue(string[] orders ,int currentOrderIndex)
{
//将来再也不会被请求的页面集合
List<Page> dontShowPageList = new List<Page>();
int start = currentOrderIndex + 1;
int end = orders.Length-1;
for (int i = 0; i < RAMDetail.Count;i++ )
{
bool pageWiilUse = false;
Page currentPage=RAMDetail[i];
//该页面在将来第一次访问 到现在的时间间隔
int timeSpanToVisit = 1;
for (int j = start; j < end; j++)
{
//计算间隔
if(currentPage.id==orders[j])
{
currentPage.timeSpanToVisit = timeSpanToVisit;
break;
}
else
{
timeSpanToVisit++;
}
}
//遍历完序列都没找到,加入集合
if (timeSpanToVisit == end-start+1)
dontShowPageList.Add(currentPage);
}
//如果不需要的少于1个
if (dontShowPageList.Count <=1 )
{
//找出最timeSpanToVisit最大的返回
int maxValue =int.MaxValue;
int maxIndex = -1;
for (int i = 0; i < RAMDetail.Count; i++)
{
if (RAMDetail[i].timeSpanToVisit >= maxValue)
{
maxValue = RAMDetail[i].timeSpanToVisit;
maxIndex = i;
}
}
return RAMDetail[maxIndex];
}
else
{//否则在不需要中找到待的最久的
return Tool.GetPageofLongest(dontShowPageList);
}
}
//获取最先进入的(在内存中待的时间最长)
public int GetIndexById(string id)
{
for (int i = 0; i < RAMDetail.Count; i++)
{
if (RAMDetail[i].id == id)
{
return i;
}
}
return -1;
}
public void processPage(List<Page> pageList, string[] orders,string flag="1")
{
Console.Write(" \n运行过程如下: \n");
//计时器
int time = 0;
//按id顺序访问页面
for (int i = 0; i < orders.Length; i++)
{
Console.WriteLine("\n------------------正在请求[" + Tool.GetPageById(pageList, orders[i]).name + "]... \n");
time++;
Page currentPage = Tool.GetPageById(pageList, orders[i]);
//有空位
if (freeSize > 0)
{
//新来的进入
ComeIn(currentPage, time);
//结束置换
FinishChage();
}
else
{//没空位
//如果没在RAM中,置换页面并产生中断
if (!IsInRAM(currentPage))
{
//中断
breakCount++;
switch (flag)
{
case "1":
{
//1先进先出(在内存中待的时间最长的先出去)
GoOut(GetPageofLongest());
}
break;
case "2":
{
//2最近最久未使用
GoOut(GetPageofRecentUnused(orders, i));
}
break;
case "3":
{
//3最优
GoOut(GetPageofLastUseInfutrue(orders, i));
}
break;
default: Console.WriteLine("输入有误,程序即将终止!"); break;
}
//新来的进入
ComeIn(currentPage, time);
//结束置换
FinishChage();
}
else
{//如果在RAM中,不置换,全都待在内存中
currentPage.VistInRAM(time);
FinishChage();
}
}
}
}
}
class Tool
{
public static Page GetPageById(List<Page> pageList,string id)
{
return pageList.Where(m => m.id == id).FirstOrDefault();
}
public static void PrintPageList(List<Page> pageList)
{
Console.Write(" \n页面文件如下: \n");
for (int i = 0; i < pageList.Count; i++)
{
pageList[i].Print(); Console.Write(" ");
}
Console.Write("\n");
}
public static void PrintOrders(string[] orders)
{
Console.Write(" \n页面访问顺序[页面ID]如下: \n");
for (int i = 0; i < orders.Length; i++)
{
Console.Write(orders[i]+" ");
}
Console.Write("\n");
}
public static Page GetPageofLongest(List<Page> pageList)
{
int maxValue = 0;
int maxIndex = 0;
for (int i = 0; i < pageList.Count; i++)
{
if (pageList[i].timeInRAM > maxValue)
{
maxIndex = i;
maxValue = pageList[i].timeInRAM;
}
}
return pageList[maxIndex];
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("----------虚拟内存页面置换算法----------- ");
List<Page> pageList = new List<Page>();
pageList.Add(new Page("0", "页面0"));
pageList.Add(new Page("1","页面1"));
pageList.Add(new Page("2", "页面2"));
pageList.Add(new Page("3", "页面3"));
pageList.Add(new Page("4", "页面4"));
pageList.Add(new Page("5", "页面5"));
pageList.Add(new Page("6", "页面6"));
string[] orders = new string[] { "6", "0", "1", "2", "0", "3", "0", "4", "2", "3" };
Tool.PrintPageList(pageList);
Tool.PrintOrders(orders);
RAM ram = new RAM(3);
Console.Write(" \n选择算法: 1-【FIFO】先进先出 2-【LRU】最近最久 3-【OPT】最佳 \n");
ram.processPage(pageList, orders,Console.ReadLine());
Console.ReadLine();
}
}
}
七、 附录
带注释的源程序,注释应清楚具体;
相关文章推荐
- Java类集学习(五)集合的输出
- 操作-postgre安装
- 070 - Climbing Stairs
- diamond淘宝框架使用
- WeUI logo专为微信设计的 UI 库 WeUI
- AngularJS基础——工具方法
- Android中View的setTag和getTag方法简述
- 深入研究mysql中group by与order by取分类最新时间内容
- POJ-3662 Telephone Lines
- Anaconda 32在windows下安装gensim
- 关于Android的.so文件所需要知道的
- 实战2--应用EL表达式显示投票结果
- 译文:前端性能的重要性 The Importance of Frontend Performance
- 有限自动机与构造
- PHP静态延迟绑定
- 【转】GATK使用方法详解(包含bwa使用)
- 数据结构课程期末总结二
- python --study address
- MVC文章汇总
- 在Nginx中配置image filter模块来实现动态生成缩略图