当前位置: 首页 > 编程日记 > 正文

linux平台的链接与加载

原文是上下两篇

  • 链接与加载(上) — 静态链接
  • 链接与加载(下) — 动态链接

    为观看方便,现在合并起来。

    一.静态链接

    示例程序

    我们先看一个简单的示例程序,代码如下:

    /*main.c*/
    int u = 333;
    int sum(int, int);
    int main(int argc, char* argv[])
    {
    sum(argc, 1);
    return 0;
    }
    


    /*sum.c*/
    #define pi 3
    int printf(const char*, ...);
    int x = 111;
    int y;
    const int w = 222;
    extern int u;
    int *ptr = &u;
    static int add(int a)
    {
    static int base = 99999;
    base--;
    return a + base;
    }
    int sum(int a, int b)
    {
    static int base = 88888;
    static int xx;
    base++;
    printf("%d\n", base);
    int t = add(a);
    return a + b + x + y + w + *ptr + t + base + pi;
    }


    编译过程

    通过一行命令(gcc -static sum.c main.c),即可编译出一个可执行程序a.out,看似简单,其实背后隐藏了一个复杂的过程:*.c文件经过预处理器(cpp)、编译器(cc1)、汇编器(as)生成可重定位目标文件*.o,然后多个可重定位目标文件经过链接器(ld),生成一个可执行目标文件a.out,如下图:

    链接器所做的事情:链接。其主要需要解决下面两个问题:

    1、符号解析:将符号引用与符号定义联系起来。

    2、重定位:将符号定义与虚拟地址关联起来,并修改所有对这些符号的引用。

    可重定位目标文件

    一般来说,我们称*.o这种文件为可重定位目标文件,a.out称为可执行目标文件,在静态链接的情况下,我们可以认为可重定位目标文件为链接器的输入,可执行目标文件为输出。实际上,各种目标文件在不同平台上,有不同的格式,例如Windows的PE格式、Linux下的ELF格式。接下来通过分析一个典型ELF可重定位目标文件,来看看链接器是如何解决上面提到的两个问题的。使用readelf -a sum.o及objdump -d sum.o可以看到sum.o的详细信息。

    一个ELF可重定位目标文件,一般包含下面这些关键section:

    像.text, .rodata, .data, .bss这些段,都比较好理解。链接器将多个可重定位目标文件合并为可以可执行程序时,首先要做的就是要合并.text, .rodata, .data, .bss这些段,如下图:

    然后根据.symtab, .rel.text, .rel.data, .strtab等section的信息,进行符号解析及重定位的关键,下面详解说明一下这几个段。

    字符串表(.strtab)

    一个字符串表,包括.symtab中的符号表的符号名,字符串表即以null结束得字符串序列,类似如下格式(可使用readelf -x获取):

    符号表(.symtab)

    存放了程序中被定义或引用的函数和全局变量(包含局部静态变量)的信息,包括符号的名字(记录的是.strtab中的偏移量),地址、大小、类型(数据、函数、段、源文件)、绑定域(本地、全局)、所属section等,示例程序sum.o的.symtab如下:

    可以看到:

    1、static修饰的局部变量,例如sum::z,add::base存放在.data section,而sum::xx放在.bss section,但是其符号名后面增加了一个数字后缀,已解决不同函数里使用相同名字的static变量,且其绑定域是LOCAL,即表示该符号是本地的,非全局可见。

    2、TYPE字段,一般常见的是FUNC、OBJECT、NOTYPE,分别表示函数、变量、未知类型(例如引用的外部变量或函数,如extern int u;以及在libc.a中定义的printf函数)。

    3、Ndx即为该符号所在的section 索引值,但有3个特殊值:ABS代表不应该被重定位的符号;UND表示未定义的符号(例如extern int u);COMMOM表示未被分配位置的未初始化数据(例如int y)。

    重定位表(.rel.xxx)与重定位

    重定位表,如rel.text为代码段的重定位表,rel.data为数据段对应的重定位表,一般而言,任何调用外部函数或全局变量的指令均需要修改。例如sum函数调用了printf函数,在未链接之前,sum.o是不知道printf函数最终真实地址的,需经过链接重定位,将printf函数关联到一个地址后,再用该地址,修改call指令。下图即为sum.o的.rel.text及.rel.data信息,为了更容易理解,将源代码及汇编代码放在一起。可以看到,sum.c编译成sum.o,里面包括全局变量(含局部静态变量)、外部函数等地址均需要重定位。

    .rel.xxx的offset表示需要进行重定位的位置(即在该section中的偏移量),info由两部分组成:后8位表示类型,例如0x01表示R_386_32,0x02表示R_386_PC32;前24位为其在.symtab中的索引值。以sum中对全局变量y的引用为例,在汇编代码中,看到在.text section的0x5d偏移处引用了y,则在.rel.text有一条对应的记录,其info信息为0x00001201,即其类型为R_386_32,前24位为0x000012,对应是y在.symtab中的索引值。静态局部变量略有不同,其在.symtab中的索引值均指向的是.data section。

    R_386_32:重定位一个使用32位绝对地址的引用。其地址计算方法为.symtab中对应的value值加上原始值,以.rel.text的第一条记录为例,其计算方法是重定位后.data section地址加上0x00000008,即add函数里的static basic地址。

    R_386_PC32:重定位一个使用32位PC相关的地址引用。其地址计算方法为用被重定位的符号的实际运行时地址,加上原始值,减去重定位所影响到的地址单元的实际运行时地址,最终算得的结果即得相对地址。例如重定位后,printf的地址是0x08048cc0,sum的地址是0x0804824c,需要重定位的地址在sum内的偏移量为0x38-0x18 = 0x20,则计算后应得的地址为0x08048cc0 - 0x0804824c - 0x20 + 0xfffffffc = 0x00000a50。sum函数中printf经过重定位后,该语句将变成 call 50 0a 00 00。

    静态库解析符号引用

    接下来,我们看看链接器是如何使用静态库来解析引用的。

    在符号解析阶段,链接器从左至右,依次扫描可重定位目标文件(*.o)和静态库(*.a)。在这个过程中,链接器将维持三个集合:

    集合E:可重定位目标文件的集合。

    集合U:未解析的符号集,即符号表中UNDEF的符号。

    集合D:已定义的符号集。

    初始情况下,E、U、D均为空。

    1、对于每个输入文件f,如果是目标文件,则将f加入E,并用f中的符号表修改U、D,然后继续下个文件。

    2、如果f是一个静态库,那么链接器将尝试匹配U中未解析符号与静态库成员定义的符号。如果静态库中某个成员m,定义了一个符号来解析U中引用,那么将m加入E中,同时使用m的符号表,来更新U、D。对静态库中所有成员目标文件反复进行该过程,直至U和D不再发生变化。此时,任何不包含在E中的成员目标文件都将丢弃,链接器将继续下一个文件。

    3、当所有输入文件完成后,如果U非空,链接器则会报错,否则合并和重定位E中目标文件,构建出可执行文件。

    对此,我们再回到文章开头的那么问题,就比较清晰了,因为libmgwapi.a以来于libdnscli.a,但是libdnscli.a放在libmgwapi.a的左边,导致libdnscli.a里的目标文件根本就没有加入集合E中。其解决办法就是交换二者顺序,当然类似与gcc demo.c -ldnscli -lmgwapi -ldnscli也是可以的。

    至此,静态链接部分大致就这些内容,下篇讲介绍动态链接与程序加载原理。

    分析工具

    1、readelf:显示目标文件的完整结构。

    2、objdump:显示一个目标文件中所有信息,可以反汇编.text。

    3、nm:列出目标文件的符号表中定义的符号。

    二.动态链接

    静态库解决了程序模块化、分离编译、提升编译效率等问题,但是也有一些明显的缺点:

    1、更新及维护困难。例如需更新静态库版本,则需要将应用程序与之重新链接。如果是一个基础类库,被几十上百个程序使用,其更新工作将是极其繁琐的。

    2、空间浪费。几乎每个进程都会使用的标准I/O函数,例如printf等,这些函数代码将被复制到每个进程的代码段中,这将会造成内存及磁盘空间的极大浪费。

    对此,动态链接共享库应运而生。

    在正式讨论动态链接之前,先留一个小问题:下面这两个编译命令有何区别?为何?

      1:  gcc -shared -o libxyz.so xyz.c
      2:  gcc -shared -fPIC -o libxyz.so xyz.c
    

    示例程序
      //xyz.c    
    //gcc -shared -fPIC -o libxyz.so xyz.c    
    int printf(const char*, ...);    
    extern int errOffset;    
    int errBase = 1;    
    int setErr()    
    {    
    errOffset = 0x888;   
    errBase = 0x999;   
    printf("setErr\n");   
    return 0;   
    }
    
    
    

    动态共享库的难点

    要想模块的更新及维护更加方便,则必须更加彻底的模块化,将程序的各个模块合理分割,形成独立的文件,并且在应用程序加载执行时,才进行链接操作。如此,只需模块与模块之间的接口保持兼容,则可以很方便的更新任意一个模块,而不需要对应用程序做任何操作。同时也能解决静态库磁盘空间浪费的问题,因为应用程序不需要再将库复制一份。

    但是内存空间的浪费,则不是那么好解决。我们先看看一下共享库中的全局变量,例如在某个共享库中,申请了一个全局变量,同时A进程与B进程都链接了该库。我们的实际使用过程中知道,A进程与B进程中这个全局变量是不会互相影响的。那么可以推断,共享库中的数据段,每个进程都有一个副本,是不能共享的,示意图如下:

    一个共享库,最核心的两个段是代码段和数据段,既然数据段不能共享(这个是理所当然的),那代码段必须能共享,否则就节省不了任何内存空间了。

    地址无关代码(PIC)

    为何需要PIC技术?

    上篇我们讲到,链接要解决的一个重要问题是重定位:即修改代码段,将全局变量或外部函数的地址替换成运行时的真实地址。如果我们仅仅是将链接过程推迟到运行时,那么这就有一个问题:例如共享库libxyz.so中有对errOffset变量的引用,且errOffset是在其他模块定义的,假设进程A中errOffset的地址是AddrA,进程B的地址是AddrB,在进程A和B的加载和重定位时,需将代码段中对errOffset的地址修改为进程对应的实际地址,而二个进程中地址不一样,则会导致二者代码段不一样,这会导致每个进程均需要拷贝一个代码段副本出来(注:如果编译共享库时没有带上-fPIC选项,就是这种效果,跟静态库的差异仅仅是将链接延迟到加载)。这样就达不到节省内存空间的效果。而要让代码段能在多个进程间共享,那必须保持代码段在重定位时,不需要被修改。于是,地址无关代码(PIC,Position-independent Code)技术诞生。

    PIC原理

    该方案的主要思想是:把代码段中跟地址相关的部分放到数据段中,使得重定位时,代码段不需要被修改。主要依赖下面两个事实:

    1、无论在何处加载一个共享库,其数据段总是紧跟在代码段之后的,即代码段中任何指令和数据段中任何变量之间的距离都是一个常量,与代码段和数据段的绝对地址无关。

    2、目标模块的数据段,在各个进程中都有对应的副本,是可以被修改的。

    于是编译器在数据段开始的地方,创建了一个表,叫做全局偏移量表(GOT,global offset table)。记录了该模块所有外部函数或全局变量的表目,同时为GOT中每个表目生成一个重定位记录。在加载时,动态链接器更新GOT中表目的值,使得其值为该符号的运行时绝对地址。

    全局数据访问的位置无关

    我们先看看全局变量是如何通过GOT技术实现位置无关代码的。还是以示例程序来分析,先看一下汇编代码。

    1: 0000055c <setErr>:

       2:   55c:   55                      push   %ebp
       3:   55d:   89 e5                   mov    %esp,%ebp
       4:   55f:   53                      push   %ebx
       5:   560:   83 ec 04                sub    $0x4,%esp
       6:   563:   e8 00 00 00 00          call   568 <setErr+0xc>
       7:   568:   5b                      pop    %ebx
       8:   569:   81 c3 94 11 00 00       add    $0x1194,%ebx
       9:   56f:   8b 83 f8 ff ff ff       mov    0xfffffff8(%ebx),%eax
      10:   575:   c7 00 88 08 00 00       movl   $0x888,(%eax)
      11:   57b:   8b 83 ec ff ff ff       mov    0xffffffec(%ebx),%eax
      12:   581:   c7 00 99 09 00 00       movl   $0x999,(%eax)
      13:   587:   83 ec 0c                sub    $0xc,%esp
      14:   58a:   8d 83 0f ef ff ff       lea    0xffffef0f(%ebx),%eax
      15:   590:   50                      push   %eax
      16:   591:   e8 c2 fe ff ff          call   458 <puts@plt>
      17:   596:   83 c4 10                add    $0x10,%esp
      18:   599:   b8 00 00 00 00          mov    $0x0,%eax
      19:   59e:   8b 5d fc                mov    0xfffffffc(%ebp),%ebx
      20:   5a1:   c9                      leave  
      21:   5a2:   c3                      ret    

    从汇编代码看,第6、7行的作用是获得当前PC值,并将其值存入寄存器ebx,第8、9行,则是计算errOffset的GOT地址,不妨假设libxyz.so映射到地址0x40018000,则执行完第7行指令后,ebx的值为0x40018000 + 0x568,执行完第9行时,eax的值为 0x40018000 + 0x568 + 0x1194 – 0x8 = 0x400196f4 = 0x40018000 + 0x16f4,而这正好就是GOT中errOffset所对应的表目地址。同理可以计算全局变量errBase所对应的GOT条目偏移量。通过下面指令,可以验证GOT中各个条目与计算是否一致:

    注:call指令的效果即将下一条指令压栈,并跳转。上面的第6行汇编,获得的效果是,0x40018000 + 0x568 被压栈,并跳转至第7行汇编(0x40018000 + 0x568),第7行的效果是,将0x40018000 + 0x568弹出,并赋给寄存器ebx,此时即完成了当前PC值的获取。

    $ objdump –R libxyz.so

       1:  DYNAMIC RELOCATION RECORDS
       2:  OFFSET   TYPE              VALUE 
       3:  ...
       4:  000016e8 R_386_GLOB_DAT    errBase
       5:  ...
       6:  000016f4 R_386_GLOB_DAT    errOffset
       7:  ...
       8:  00001708 R_386_JUMP_SLOT   puts
       9:  ...

    函数的延迟绑定

    为何需要延迟绑定技术?

    位置无关代码,在性能上,比静态链接要差一些,要访问一个全局变量,需要先定位到GOT地址,然后间接寻址。另外一个降低程序性能的因素是,动态链接的工作是在加载时完成的,即程序启动后,动态链接库先要完成链接过程,即需寻找并加载所需的共享库,进行符号搜索和重定位,这无疑会影响程序的启动速度,于是就有延迟绑定技术(PLT,Procedure Linkage Table)。

    在动态链接下,程序各个模块之间包含了大量的函数调用(全局变量较少,否则大量全局变量会增加模块之间的耦合度,范围了模块之间松耦合的原则)。但是往往有很多函数,在整个程序执行过程中,都不会被调用,例如一些错误处理函数,如果一开始全部都在程序启动时进行链接,则会造成浪费。PLT技术,则是当函数第一次被使用时才进行链接(符号解析、重定位),如果没有用到则不进行链接。

    延迟绑定原理

    参考上面汇编代码中,对printf函数的调用,实际上是跳到puts@plt的地址,其汇编代码如下:

       1:  Disassembly of section .plt:
       2:          ...
       3:  00000458 <puts@plt>:
       4:   458:   ff a3 0c 00 00 00       jmp    *0xc(%ebx)
       5:   45e:   68 00 00 00 00          push   $0x0
       6:   463:   e9 e0 ff ff ff          jmp    448 <_init+0x18>
       7:          ...

    在上面对全局变量的分析中,已知ebx的值为0x40018000 + 0x568 + 0x1194,上面的第4行汇编,即是跳转至0x40018000 + 0x568 + 0x1194 + 0xc = 0x40018000 + 0x1708处(此即puts对应的GOT地址)所存储的地址。如果该函数还未被调用过,则该GOT条目的值被初始化为0x40018000 + 0x45e,即上面的第5行汇编代码地址,此时第4行的作用,就是跳转到第5行。其中0x0表示puts这个符号在.rel.plt中的索引值,以此作为一个参数,调用动态链接器,完成符号解析和重定位操作,并将puts函数的真实地址填入puts@GOT中。后续再次调用puts函数时,通过第4行即可直接跳转到puts函数的入口。

    总体来说,动态链接的示意图如下:

    同名全局符号覆盖(global symbol interpose)

    在使用动态链接库时,必须小心该问题。例如下面这个main.c与libxyz.so编译(gcc -o b.out -g main.c -L./ -lxyz)时,不会报任何错误。最终main函数中setErr函数调用的是main.c文件中定义的,而不是libxyz.so中定义的。

       1:  int errOffset = 333;
       2:  extern int errBase;
       3:   
       4:  int setErr()
       5:  {
       6:      errOffset = 888;
       7:      errBase = 999;
       8:      return 0;
       9:  }
      10:   
      11:  int main(int argc, char* argv[]) 
      12:  {
      13:      setErr();
      14:      printf("%d, %d\n", errOffset, errBase);
      15:      return 0;
      16:  }

    对于这个问题,linux下动态链接库采用如下处理方式:当一个符号需求被加入全局符号表时,如果同名符号已存在,则忽略后加入的符号。一般动态链接器的加载顺序,是按广度优先顺序进行加载,首先是main,然后是libxyz.so,然后是libc.so等。

    总结

    现在我们简单回顾一下,链接与编译等过程的分离,使得代码的分离编译,模块化成为可能。而链接过程解决的两个核心问题是符号解析与重定位:符号解析即相当于将符号与运行时地址关联起来,而重定位则是修正代码段或数据段中的全局变量或函数的地址。静态链接库在链接时,将模块中相应目标文件的代码段和数据段直接修正后,拷贝到可执行目标文件中;而动态链接共享库,与应用程序进一步分离,并将链接过程延迟到程序加载时进行,同时通过PIC技术,使得重定位时,仅需要修改数据段,而无需修改代码段,于是代码段可以被多个进程共享,以达到节省内存空间效果。

    无论是静态链接还是动态链接,抛开这些技术细节本身,还有很多其他思想是值得借鉴的:

    1、坚决的模块化。小到代码级函数,大到大规模系统的功能Service化,无一不是模块化的体现。将C语言代码转换成可执行程序,就要经过预处理、编译、汇编、链接等模块的依此处理,这几个模块之间功能清晰,职责明确,使得这个复杂的过程变得清晰简洁,实为模块化设计的典范。至于如何才能做到这种高内聚松耦合的模块化,可以参阅《Unix编程艺术》一书,该书中有部分章节详细谈了模块化的几大原则:正交性、紧凑性等。

    2、Don't Repeat yourself。不重复造轮子在不同层面有上不同的体现,总的来说就是不要让相同或相似的东西重复出现,如果几行代码经常重复出现,就应该写成函数;如果一个文件在不同程序中重复出现,那就应该编译成库文件。动态共享库相对于静态库,在复用上更进一步:不要让类似的二进制代码重复出现在内存里。

    3、只有必须要做的时候才去做。动态库的延迟绑定技术、被广泛应用的copy on write(COW)技术都是这种思路,如果在合适的场景使用,不仅能提升效率,还能节省资源。

    参考资料

    1、《深入理解计算机系统》。

    2、《程序员的自我修养》。

相关文章:

预训练模型ProphetNet:根据未来文本信息进行自然语言生成

作者 | 刘大一恒、齐炜祯、晏宇、宫叶云、段楠、周明来源 | 微软研究院AI头条&#xff08;ID:MSRAsia&#xff09;编者按&#xff1a;微软亚洲研究院提出新的预训练模型 ProphetNet&#xff0c;提出了一种新的自监督学习目标——同时预测多个未来字符&#xff0c;在序列到序列的…

模拟进程管理小结,编码规范的重要性

废话不多说了&#xff0c;省的又有衰人找我麻烦。希望我讨厌的&#xff0c;和讨厌我的少来骚扰我&#xff0c;由衷的感谢它们。 我不回那些骚扰&#xff0c;是因为我见到名字就直接删了&#xff0c;看都懒的看了。也别怪我粗鲁&#xff0c;因为我一向是对什么人说什么话 的&…

JSPServlet路径问题

2019独角兽企业重金招聘Python工程师标准>>> 如果带WebRoot&#xff0c;那么js、css、img都应该放到WebRoot目录下&#xff0c;否则访问会有问题。千万不要放在WEB-INF下&#xff0c;因为WEB-INF下的内容只有服务器转发可以访问到&#xff0c;出于安全考虑。 如果不…

Git学习教程(六)Git日志

第六课 Git 日志 内容提要&#xff1a;浏览项目历史&#xff0c;查询指定提交内容&#xff0c;图形化显示分枝和合并...git log是git中最常用的一个命令&#xff0c;执行之后&#xff0c;会显示该项目的提交历史。如果命令不加任何参数&#xff0c;那么就会显示目前所在分枝上&…

汇编包含C代码

反汇编的时候带上C代码便于观察 比较三元表达式和if else的差异 a1.c #include <stdio.h> int main(void) { int a1;int b2;int c0;a (b>c)?1:0;return 0;} a2.c #include <stdio.h> int main(void) { int a1;int b2;int c0;if(b>c){a1;}else{a0;…

无需3D运动数据训练,最新人体姿势估计方法达到SOTA | CVPR 2020

作者 | Muhammed Kocabas译者 | 刘畅出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;人体的运动对于理解人的行为是非常重要的。尽管目前已经在单图像3D姿势和动作估计方面取得了进展&#xff0c;但由于缺少用于训练的真实的3D运动数据&#xff0c;因此现有的基于视频…

Linux内核跟踪之trace框架分析【转】

转自&#xff1a;http://blog.chinaunix.net/uid-20543183-id-1930846.html------------------------------------------本文系本站原创,欢迎转载!转载请注明出处:http://ericxiao.cublog.cn/------------------------------------------一: 前言本文主要是对trace的框架做详尽…

写给Python开发者:机器学习十大必备技能

作者 | Pratik Bhavsar译者 | 明明如月&#xff0c;编辑 | 夕颜来源 | CSDN&#xff08;ID:CSDNnews&#xff09;有时候&#xff0c;作为一个数据科学家&#xff0c;我们常常忘记了初心。我们首先是一个开发者&#xff0c;然后才是研究人员&#xff0c;最后才可能是数学家。我…

Linux环境程序栈溢出原理

当在缓冲区中输入过多的数据时&#xff0c;缓冲区溢出就会发生&#xff0c;C语言提供了多种方法&#xff0c;可以使在缓冲区中输入的数据比预期的多。 局部变量可以被分配到栈上。这就意味着在栈的某个地方有一个固定大小的缓冲区。 而栈是向下增长的&#xff0c;而且一些重要…

[翻译]Joomla 1.5架构(十一) model 包

这个包包含了跟数据表交互的所有相关类 JModel This abstract class is the base class for all Joomla! data access objects. 所有数据访问类的抽象基类。 以下的类都分别实现对不同表的访问&#xff0c;不再翻译了。 Adapter Folder JModelCategory This is a data access …

度量快速开发平台端口映射的介绍

度量快速开发平台在客户中部署的时候&#xff0c;可能会想内网与外网用户同时使用。一般情况下&#xff0c;服务端都是部署在内网的&#xff0c;那外网用户要访问&#xff0c;就可能用到端口映射的功能。端口映射基本都是在路由器上进行。下面就是几个常用的路由器上的设置方法…

为什么栈和堆的生长方向不一样

栈的生长方向 8051的栈是向高地址增长&#xff0c;INTEL的8031、8032、8048、8051系列使用向高地址增长的堆栈&#xff1b;但同样是INTEL&#xff0c;在x86系列中全部使用向低地址增长的堆栈。其他公司的CPU中除ARM的结构提供向高地址增长的堆栈选项外&#xff0c;多数都是使用…

简单粗暴理解与实现机器学习之逻辑回归:逻辑回归介绍、应用场景、原理、损失以及优化...

作者 | 汪雯琦责编 | Carol来源 | CSDN 博客出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;学习目标知道逻辑回归的损失函数知道逻辑回归的优化方法知道sigmoid函数知道逻辑回归的应用场景应用LogisticRegression实现逻辑回归预测知道精确率、召回率指标的区别知道如…

生命的脆弱——悼念朋友

生命的脆弱让我们敲希望的钟啊多少祈祷在心中让大家看不到失败叫成功永远在让地球忘记了转动啊四季少了夏秋冬让宇宙关不了天窗叫太阳不西沉让欢喜代替了哀愁啊微笑不会再害羞让时光懂得去倒流叫青春不开溜让贫穷开始去逃亡啊快乐健康留四方让世界找不到黑暗幸福像花开放让大家…

VMware Tools手动下载

2019独角兽企业重金招聘Python工程师标准>>> VMware自己下载VMware Tools非常慢。你可以自己手动下载它。 下载地址为&#xff1a; version: 8.8.2 http://softwareupdate.vmware.com/cds/vmw-desktop/ws/8.0.3/ 选择最新的build&#xff0c;例如&#xff1a; http:…

Linux查看多核CPU利用率

1.top 使用权限&#xff1a;所有使用者 使用方式&#xff1a;top [-] [d delay] [q] [c] [S] [s] [i] [n] [b] 说明&#xff1a;即时显示process的动态 d :改变显示的更新速度&#xff0c;或是在交谈式指令列( interactive command)按s q :没有任何延迟的显示速度&#xf…

仓央嘉措《那一天,那一月,那一年,那一世》

那一天&#xff0c;   我闭目在经殿的香雾中&#xff0c;   蓦然听见你颂经中的真言&#xff1b;     那一月&#xff0c;   我摇动所有的经筒&#xff0c;   不为超度&#xff0c;   只为触摸你的指尖&#xff1b;     那一年&#xff0c;   磕长头匍匐在…

AI+大数据助力抗疫,带你认识百度地图的新玩法!

作者 | Aholiab责编 | Carol出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;“喂&#xff0c;你好&#xff0c;我是百度地图的客服&#xff0c;请问是xx店铺对吗&#xff1f;”“嗯&#xff0c;什么事&#xff1f;”“您家在疫情期间还照常营业&#xff0c;对吗&…

Coursera Machine Learning 作业提交问题

关于作业提交问题的解决办法 Octave 4.0.0无法正常提交 解决办法&#xff1a;打两个补丁 补丁1&#xff1a;平台通用补丁2&#xff1a;Win&#xff0c;Linux or Mac 注&#xff1a;补丁文件中有安装说明

Linux查看进程内存状况

查看全部进程 通过top或ps -ef | grep 进程名 得到进程的PID。该命令可以提供进程状态、文件句柄数、内存使用情况等信息。 #pa aux 先查看进程 nginx的工作进程是5757 pmap命令 可以显示一个或多个进程所使用的内存数量。你可以使用这个工具来了解服务器上的某个进程分配…

用于小型图形挖掘研究的瑞士军刀:空手道俱乐部的图表学习Python库

作者 | Benedek Rozemberczki译者 | 天道酬勤 责编 | Carol出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;空手道俱乐部&#xff08;Karate Club&#xff09;是NetworkX Python软件包的无监督机器学习扩展库。详细可以参阅此处的文档&#xff1a;https://github.com…

电子商务创造的第二次产业机会

即将迎来冬至节气的这个周末&#xff0c;天寒地冻&#xff0c;却是电子商务的饕餮之季。淘宝网商交易大会刚刚在成都落下帷幕&#xff0c;而比网货交易会更令业界期待的“2009中国电子商务创新发展高峰论坛”也在北京顺利召开。大会由国内最大的电子商务软件及服务提供商ShopEx…

C#趣味程序---个位数为6,且能被3整出的五位数

using System;namespace ConsoleApplication1 {class Program{static void Main(string[] args){int count 0;int k;for (int i 1000; i < 9999; i){k i * 10 6;if (k % 3 0){Console.WriteLine(k);count;}}Console.WriteLine(count); }} }

c# winform 用子窗体刷新父窗体,子窗体改变父窗体控件的值

第一种方法: 用委托,Form2和Form3是同一组 Form2 usingSystem; usingSystem.Collections.Generic; usingSystem.ComponentModel; usingSystem.Data; usingSystem.Drawing; usingSystem.Text; usingSystem.Windows.Forms; namespaceTestMouseMove { pub…

TCMalloc

tcmalloc 业界最有名的内存分配库&#xff0c;当数google 的tcmalloc。Tcmalloc 在管理小 内存块时非常有效&#xff0c;而且能够避免在大内存分配时的mmap()系统调用。它在多 线程中的表现也不错能很好的减少锁碰撞(glibc 致命的问题)。Tcmalloc 现在基 本上成了mysql DBA 的标…

前沿技术探秘:知识图谱构建流程及方法

作者 | 郑毅封图| CSDN│下载于视觉中国出品 | CSDN云计算&#xff08;ID&#xff1a;CSDNcloud&#xff09;随着AI技术的发展和普及&#xff0c;当今社会已经进入了智能化时代。与以往不同的是&#xff0c;在这一波浪潮中&#xff0c;企业不仅是向数字化转型&#xff0c;更是向…

【HDOJ】3275 Light

这就是个简单线段树延迟标记。因为对bool使用了~而不是&#xff01;&#xff0c;wa了一下午找不到原因。 1 /* 3275 */2 #include <iostream>3 #include <sstream>4 #include <string>5 #include <map>6 #include <queue>7 #include <set>…

lighttpd+PHP安装

lighttpd版本&#xff1a;1.4.32 php版本&#xff1a;5.4.11 2013.2.3第一次 php版本&#xff1a;5.4.12 2013.3.14第二次修改 1.lighttpd官网地址 http://www.lighttpd.net 2.下载安装lighttpd #wget http://download.lighttpd.net/lighttpd/releases-1.4.x/lighttp…

描述C#多线程中 lock关键字

本文介绍C# lock关键字&#xff0c;C#提供了一个关键字lock&#xff0c;它可以把一段代码定义为互斥段&#xff08;critical section&#xff09;&#xff0c;互斥段在一个时刻内只允许一个线程进入执行&#xff0c;而其他线程必须等待。 每个线程都有自己的资源&#xff0c;但…

从样本处理到决策模型,如何用NLP识别盗版资源?

作者 | 阿里文娱高级开发工程师千起出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;背景随着5G时代来临&#xff0c;新媒体行业快速发展&#xff0c;盗版传播平台多样化、形式多样化&#xff0c;版权方难以通过有限的人力实现最大限度的维权。根据MUSO报告显示2017年…