冯诺依曼体系:将程序指令和数据一起设计的计算机设计概念结构
必须有一个存储器、必须有一个控制器、运算器、输入设备、输出设备
冯诺伊曼瓶颈:存储器的速度跟不上CPU的速度,指磁盘、内存、寄存器。
程序翻译与程序解释
较为高级的计算机语言通过编译器生成较为低级的计算机语言。
1G->1024MB->10241024KB->10241024KB1024B(字节)->10241024KB1024B8bit(比特位)
存储器:CPU高速缓存、内存条、硬盘。
内存(RAM random access memory)通过电容来存储数据。
高速缓存在CPU中,主存即为内存,辅存即为磁盘。高速缓存解决CPU和主存速度不一致的问题。
高速缓存中存储CPU需要的数据。如果不存在,则需要去主存中读取。
高速缓存替换策略
1 随机算法(每次随机替换高速缓存中的数据)
2 先进先出(FIFO 把高速缓存看成一个队列,CPU执行替换时,将会将队头中数据淘汰,重复读取数据不会改变数据在缓存中的位置,)
3 最不经常使用算法(LFU(Last Fequently Used)优先淘汰不经常使用的数据,有一块区域会记录字块的使用频率,设计的数据结构可以为一个map,key为频率,value为该频率下的节点,即内存中的块)
4 最近最少使用算法。(LRU (Last Recently User),同样使用队列存储使用的数据,将使用的数据移动到队头,这样 ,使用次数多的一定在队头,执行淘汰策略的时候淘汰队尾的数据)
LFU强调的是一段时间内的频率。
LRU强调的是一段时间内的使用次数。这两个算法不能划等号,比如某个缓存块之前一段时间的访问频率比较高,但是已经好久没被使用了,按照LFU算法,是会被淘汰的,同样,如果一个缓存块是新加入的,访问次数比较低,按照LFU是会被淘汰的,但是按照LRU算法是不会被淘汰的。
LRU算法实现
采用链表存储数据节点,每次将数据添加到数据队尾,链表中的数据如果被访问到了那么将该节点断开,添加到队尾,核心方法如下:
public int get(int key) {
print();
Node node = this.tail;
while (node != null) {
if (Objects.equals(node.key, key)) {
moveNodeToTail(node);
return node.value;
}
node = node.before;
}
return -1;
}
/**
* 将node节点添加到队尾
* @param node
*/
private void moveNodeToTail(Node node) {
if (this.tail == node) {
// 不用移动
return;
}
//node的前后不要指向node
if (node.before == null) {
//不存在前置节点
this.head = node.after;
} else {
node.before.after=node.after;
}
node.after.before = node.before;
this.tail.after = node;
node.before = this.tail;
node.after = null;
this.tail = node;
}
public void put(int key, int value) {
print();
// 是否存在
Node node = this.tail;
while (node != null) {
if (Objects.equals(node.key, key)) {
// 覆盖之前的值
node.value = value;
moveNodeToTail(node);
return;
}
node = node.before;
}
if (this.currNodeSize >= this.capacity) {
// 发生淘汰策略
eliminateNode();
}
Node putNode = new Node(key, value);
if (this.currNodeSize==0) {
// 为第一个节点
this.head = putNode;
} else {
// 不是第一个节点
putNode.before = this.tail;
this.tail.after = putNode;
}
this.tail = putNode;
this.currNodeSize++;
return;
}
/**
* 发生淘汰策略
*/
private void eliminateNode() {
Node node = this.head;
// 移除个数
int eliminateNum = this.currNodeSize - this.capacity + 1;
for (int i = 1; i <= eliminateNum; i++) {
node = node.after;
}
if(node!=null) {
if(node.before!=null) {
node.before.after=null;
node.before=null;
}
}
this.head = node;
this.currNodeSize = this.currNodeSize - eliminateNum;
}
参考:https://blog.csdn.net/u013164931/article/details/82803298
部分图片摘自某课网。