虚调用
虚调用的定义
虚调用 是相对于 实调用 而言,它的本质是 动态联编 。
在发生函数调用的时候,如果函数的入口地址是在编译阶段静态确定的,就是是 实调用 。
如果函数的入口地址要在运行时通过查询虚函数表的方式获得,就是 虚调用 。
虚函数 的几种 实调用 的情形不通过指针或者引用调用虚函数
虚调用 不能简单的理解成 “对虚函数的调用” ,因为对虚函数的调用很有可能是实调用。
12345678910111213141516171819202122232425262728293031#include <iostream>using namespace std;class A {public: virtual void show() { cout << "In A" << endl; }};class B : public A {public: void show() { cout << "I ...
虚函数与虚表
虚函数与虚表
普通类的内存布局和带虚函数类的内存布局123456789101112131415161718192021#include <iostream>using namespace std;class NonVirtualClass {public: void foo(){}};class VirtualClass {public: virtual void foo(){}};int main() { cout << "Size of NonVirtualClass: " << sizeof(NonVirtualClass) << endl; cout << "Size of VirtualClass: " << sizeof(VirtualClass) << endl;}
这里 NonVirtualClass 的大小为1,而 Vir ...
数字大写转换
该算法未经过大量数据验证!!!
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061#include <iostream>#include <string>using namespace std;string chinese[] = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};string bit[] = {"", "十", "百", "千"};string GetChinese(string num){ ...
C++ 的几种类型转换
C++ 的几种类型转换
在 C 语言中,我们大多数是用 (type_name) expression 这种方式来做强制类型转换,但是在 C++ 中,更推荐使用四个转换操作符来实现显式类型转换:
static_cast
dynamic_cast
const_cast
reinterpret_cast
static_cast
用法: static_cast <new_type> (expression) 。其实 static_cast 和 C 语言 () 做强制类型转换基本是等价的。主要用于以下场景:
基本类型之间的转换
将一个基本类型转换为另一个基本类型,例如将整数转换为浮点数或将字符转换为整数。
12int a = 42;double b = static_cast<double>(a); // 将整数a转换为双精度浮点数b
指针类型之间的转换
将一个指针类型转换为另一个指针类型,尤其是在类层次结构中从基类指针转换为派生类指针。这种转换不执行运行时类型检查,可能不安全,要自己保证指针确实可以互相转换。
12345class Base { ...
碎玉零珠————计算机组成原理
什么是缓存(Cache)?为什么需要缓存?如何提高缓存的命中率?缓存是不是最快的?
Cache即CPU的高速缓冲存储器,是一种是用于减少处理器访问内存所需平均时间的部件;
由于CPU的计算速度远远大于从CPU向内存取数据的速度,如果每次都让CPU去内存取数据,会导致CPU计算能力的浪费,所以人们设计了缓存,CPU通过读写缓存来获取操作数,结果也通过缓存写入内存;
注意程序的局部性原理,在遍历数组时按照内存顺序访问;充分利用CPU分支预测功能,将预测的指令放到缓存中执行;此外缓存的容量和块长是影响缓存效率的重要因素。
缓存不是最快的,寄存器更快。
附 Cache 的基本原理
编译器、汇编器和链接器的基本概念编译器
编译器把高级语言翻译为机器语言
得到 hello.s 文件,这个是汇编语言程序
不同的高级语言翻译的汇编语言相同
汇编器
汇编器将 hello.s 翻译成机器语言指令,把这些指令打包成可重定位目标程序。
得到 .o 文件,是一个二进制文件,它的字节码是机器语言指令,不再是字符。前面两个阶段都还有字符。
链接器
链接器负责 .o 文件的合并。得到的是可执行目标文件。
gcc ...
Cache的基本原理
为什么需要Cache程序是如何运行起来的
程序是运行在 RAM(随机存储器) 之中,我们称之为 main memory(主存)。当我们需要运行一个进程的时候,首先会从磁盘设备(例如,eMMC、UFS、SSD等)中将可执行程序load到主存中,然后开始执行。
在CPU内部存在一堆的通用寄存器(register)。如果 CPU 需要将一个变量(假设地址是A)加1,一般分为以下3个步骤:
CPU 从主存中读取地址 A 的数据到内部通用寄存器 x0(ARM64架构的通用寄存器之一)。
通用寄存器 x0 加1。
CPU 将通用寄存器 x0 的值写入主存。
其实现实中,CPU通用寄存器的速度(< 1ns)和主存(~ 65ns)之间存在着太大的差异。
因此,上面举例的3个步骤中,步骤1和步骤3实际上速度很慢。当CPU试图从主存中 Load / Store 操作时,由于主存的速度限制,CPU不得不等待这漫长的65ns时间。
如果我们采用更快材料制作更快速度的主存,并且拥有几乎差不多的容量, 其成本将会大幅度上升。我们试图提升主存的速度和容量,又期望其成本很低,这就有点难为人了。
因此, ...
Cache对代码的影响
问题背景
代码片段一
12345int array[10][128];for (i = 0; i < 10; i++) for (j = 0; j < 128; j++) array[i][j] = 1;
代码片段二
12345int array[10][128];for (i = 0; i < 128; i++) for (j = 0; j < 10; j++) array[j][i] = 1;
我们假设使用的L1 Cache Line大小是64字节,采用写分配及写回策略。继续假设数组 array 内存首地址是64字节对齐。
问题分析
在有了以上背景假设后,我们先分析下片段1导致的Cache Miss / Hit情况。
当执行 array[0][0] = 1 时,Cache 控制器发现 array[0][0] 的值不在Cache中,此时发生一次 Cache Miss。然后从主存中读取 array[0][0] 到 array[0][15] 的内存值到 Cache 中。
当执行访问 array[0][1] = 1 ...
页面置换算法
页面置换算法简介
进程运行时,若其访问的页面不在内存而需将其调入(缺页异常),但内存已无空闲空间时,就需要从内存中调出一页程序或数据,送入磁盘的对换区,其中选择调出页面的算法就称为页面置换算法。
好的页面置换算法应有较低的页面更换频率,也就是说,应将以后不会再访问或者以后较长时间内不会再访问的页面先调出。
页面置换算法的目标是最小化缺页中断的次数,常见的页面置换算法有最佳⻚⾯置换算法(OPT)、先进先出置换算法(FIFO)、最近最久未使⽤的置换算法(LRU)、时钟页面置换算法和最不常⽤置换算法等。
最佳页面置换算法(淘汰未来不会使用/最长时间不访问的页面)
理论上的最佳算法,因为它可以保证最低的缺页率。但在实际应用中,由于无法预知未来的访问模式,OPT 通常无法实现。
先进先出置换算法(优先淘汰最早进入内存的页面)
FIFO 算法维护一个队列,新来的页面加入队尾,当发生页面置换时,队头的页面(即最早进入内存的页面)被移出。
FIFO 和 OPT 算法的区别在于:除了在时间上向后或向前看之外,FIFO 算法使用的是页面调入内存的时间,OPT 算法使用的是页面将来使用的时间
...
碎玉零珠————计算机操作系统
并发与并行
并发:在一段时间内,多个任务都会被处理。但在某一时刻,只有一个任务在执行。单核处理器做到的并发,其实是利用时间片的轮转,例如有两个进程 A 和 B,A 运行一个时间片之后,切换到 B,B 运行一个时间片之后又切换到 A。因为切换速度足够快,所以宏观上表现为在一段时间内能同时运行多个程序。
并行:在同一时刻,有多个任务在执行。这个需要多核处理器才能完成,在微观上就能同时执行多条指令,不同的程序被放到不同的处理器上运行,这个是物理上的多个进程同时进行。
进程的状态
运⾏状态(Runing):该时刻进程占用 CPU;
就绪状态(Ready):可运行,由于其他进程处于运行状态而暂时停止运行;
阻塞状态(Blocked):该进程正在等待某⼀事件发生(如等待输⼊/输出操作的完成)而暂时停止运行,这时,即使给它 CPU 控制权,它也无法运行;
创建状态(new):进程正在被创建时的状态;
结束状态(Exit):进程正在从系统中消失时的状态;
进程与线程
进程是一个正在执行的程序的实例。每个进程有自己独立的地址空间、全局变量、堆栈、和文件描述符等资源。
线程是进程中的一个执行单元。 ...














