SQLite3源程序分析之虚拟机

本文深入探讨了SQLite3的虚拟机,与Java虚拟机进行对比,详细介绍了SQLite3虚拟机的内部结构,包括指令、栈、指令计数器和解释引擎的工作原理。通过对SQL语句的编译和执行过程的分析,揭示了SQLite3虚拟机如何高效地处理数据库查询。
摘要由CSDN通过智能技术生成

SQLite3源程序分析之虚拟机

前言

  最早的虚拟机可追溯到IBM的VM/370,到上个世纪90年代,在计算机程序设计语言领域又出现一件革命性的事情——Java语言的出现,它与c++最大的不同在于它必须在Java虚拟机上运行。Java虚拟机掀起了虚拟机技术的热潮,随后,Microsoft也不甘落后,雄心勃勃的推出了.Net平台。首先将SQLite虚拟机与Java虚拟机作对比。

1、概述

  所谓虚拟机是指对真实计算机资源环境的一个抽象,它为解释性语言程序提供了一套完整的计算机接口。虚拟机的思想对现在的编译有很大影响,其思路是先编译成虚拟机指令,然后针对不同计算机实现该虚拟机。
  虚拟机定义了一组抽象的逻辑组件,这些组件包括寄存器组、数据栈和指令集等等。

虚拟机指令的解释执行包括3步:
 1. 获取指令参数;
 2. 执行该指令对应的功能;
 3. 分派下一条指令。
其中第一步和第三步构成了虚拟机的执行开销。

  很多语言都采用了虚拟机作为运行环境。作为下一代计算平台的竞争者,Sun的Java和微软的.NET平台都采用了虚拟机技术。Java的支撑环境是Java虚拟机(Java Virtual Machine,JVM),.NET的支撑环境是通用语言运行库(Common Language Runtime,CLR)。JVM是典型的虚拟机架构。
  Java平台结构如图所示。从图中可以看出,JVM处于核心位置,它的下方是移植接口。移植接口由依赖平台的和不依赖平台的两部分组成,其中依赖于平台的部分称为适配器。JVM通过移植接口在具体的操作系统上实现。如果在Java操作系统(Java Operation System, JOS)上实现,则不需要依赖于平台的适配器,因为这部分工作已由JOS完成。因此对于JVM来说,操作系统和更低的硬件层是透明的。在JVM的上方,是Java类和Java应用程序接口(Java API)。在Java API上可以编写Java应用程序和Java小程序(applet)。所以对于Java应用程序和applet这一层次来说,操作系统和硬件就更是透明的了。我们编写的Java程序,可以在任何Java平台上运行而无需修改。

 

  JVM定义了独立于平台的类文件格式和字节码形式的指令集。在任何Java程序的字节码表示形式中,变量和方法的引用都是使用符号,而不是使用具体的数字。由于内存的布局要在运行时才确定,所以类的变量和方法的改变不会影响现存的字节码。例如,一个Java程序引用了其他系统中的某个类,该系统中那个类的更新不会使这个Java程序崩溃。这也提高了Java的平台独立性。

  虚拟机一般都采用了基于栈的架构,这种架构易于实现。虚拟机方法显著提高了程序语言的可移植性和安全性,但同时也导致了执行效率的下降。

2、Java虚拟机 

2.1、概述

  Java虚拟机的主要任务是装载Class文件并执行其中的字节码。Java虚拟机包含一个类装载器(class  loader),它从程序和API中装载class文件,Java API中只有程序执行时需要的那些类才会被装载,字节码由执行引擎来执行。
  不同的Java虚拟机,执行引擎的实现可能不同。在软件实现的虚拟机中,一般有以下几种实现方式:
  (1)解释执行:实现简单,但速度较慢,这是Java最初阶段的实现方式。
  (2)即时编译(just-in-time):执行较快,但消耗内存。在这种情况下,第一次执行的字节码会编译成本地机器代码,然后被缓存,以后可以重用。
  (3)自适应优化器:虚拟机开始的时候解释字节码,但是会监视程序的运行,并记录下使用最频繁的代码,然后把这些代码编译成本地代码,而其它的代码仍保持为字节码。该方法既提高的运行速度,又减少了内存开销。
  同样,虚拟机也可由硬件来实现,它用本地方法执行Java字节码。

2.2、Java虚拟机

  Java虚拟机的结构分为:类装载子系统,运行时数据区,执行引擎,本地方法接口。其中运行时数据区又分为:方法区,堆,Java栈,PC寄存器,本地方法栈。

 

3、SQLite虚拟机 

  在SQLite的后端(backend)的上一层,通常叫做虚拟数据库引擎(virtual database engine),或者叫做虚拟机(virtual machine)。从作用上来说,它是SQLite的核心。用户程序发出的SQL语句请求,由前端(frontend)编译器处理,生成字节代码程序(bytecode programs),然后由VM解释执行。VM执行时,又会调用B-tree模块的相关的接口,并输出执行的结果(本节将以一个具体的查询过程来描述这一过程)。

3.1、虚拟机的内部结构

  先来看一个简单的例子:

复制代码
int main(int argc, char **argv)
{
    int rc, i,  id, cid; 
    char *name;
    char *sql;
    char *zErr;
    sqlite3 *db; sqlite3_stmt *stmt;
    sql="select id,name,cid from episodes";
    //打开数据库
    sqlite3_open("test.db", &db);
    //编译sql语句
    sqlite3_prepare(db, sql, strlen(sql), &stmt, NULL);
    //调用VM,执行VDBE程序
    rc = sqlite3_step(stmt);    
    while(rc == SQLITE_ROW) {
        id = sqlite3_column_int(stmt, 0);
        name = (char *)sqlite3_column_text(stmt, 1);
        cid = sqlite3_column_int(stmt, 2);
        if(name != NULL){
            fprintf(stderr, "Row:  id=%i, cid=%i, name='%s'\n", id,cid,name);
        } else {
            /* Field is NULL */
            fprintf(stderr, "Row:  id=%i, cid=%i, name=NULL\n", id,cid);
        } 
        rc = sqlite3_step(stmt);
    }
    //释放资源
    sqlite3_finalize(stmt);
    //关闭数据库
    sqlite3_close(db);
    return 0;
}
复制代码

  这段程序很简单,它的功能就是遍历整个表,并把查询结果输出。
  在SQLite 中,用户发出的SQL语句,都会由编译器生成一个虚拟机实例。在上面的例子中,变量sql代表的SQL语句经过sqlite3_prepare()处理后,便生成一个虚拟机实例——stmt。虚拟机实例从外部看到的结构是sqlite3_stmt所代表的数据结构,而在内部,是一个vdbe数据结构代表的实例。
  关于这点可以看看它们的定义:

//sqlite3.h
typedef struct sqlite3_stmt sqlite3_stmt;

  vdbe的定义

复制代码
//虚拟机数据结构 vdbeInt.h
struct Vdbe {
  sqlite3 *db;        /* The whole database */
  Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
  FILE *trace;        /* Write an execution trace here, if not NULL */
  int nOp;            /* Number of instructions in the program(指令的条数) */
  int nOpAlloc;       /* Number of slots allocated for aOp[]*/
  Op *aOp;            /* Space to hold the virtual machine's program(指令)*/
  int nLabel;         /* Number of labels used */
  int nLabelAlloc;    /* Number of slots allocated in aLabel[] */
  int *aLabel;        /* Space to hold the labels */
  Mem *aStack;        /* The operand stack, except string values(栈空间) */
  Mem *pTos;          /* Top entry in the operand stack(栈顶指针) */
  Mem **apArg;        /* Arguments to currently executing user function */
  Mem *aColName;      /* Column names to return */
  int nCursor;        /* Number of slots in apCsr[] */
  Cursor **apCsr;     /* One element of this array for each open cursor(游标数组) */
  int nVar;           /* Number of entries in aVar[] */
  Mem *aVar;          /* Values for the OP_Variable opcode*/
  char **azVar;       /* Name of variables */
  int okVar;          /* True if azVar[] has been initialized */
  int magic;              /* Magic number for sanity checking */
  int nMem;               /* Number of memory locations currently allocated */
  Mem *aMem;              /*
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值