c++后端开发资料整理学习

brk是系统调用,主要工作是实现虚拟内存到内存的映射,可以让进程的堆指针增长一定的大小,逻辑上消耗掉一块虚拟地址空间,malloc向OS获取的内存大小比较小时,将直接通过brk调用获取虚拟地址。

mmap是系统调用,也是实现虚拟内存到内存的映射,可以让进程的虚拟地址区间切分出一块指定大小的虚拟地址空间vma_struct,一个进程的所有动态库文件.so的加载,都需要通过mmap系统调用映射指定大小的虚拟地址区间,被mmap映射返回的虚拟地址,逻辑上被消耗了,直到用户进程调用unmap,会回收回来。malloc向系统获取比较大的内存时,会通过mmap直接映射一块虚拟地址区间。

malloc是C语言标准库中的函数,主要用于申请动态内存的分配,其原理是当堆内存不够时,通过brk/mmap等系统调用向内核申请进程的虚拟地址区间,如果堆内部的内存能满足malloc调用,则直接从堆里获取地址块返回。

new是C++内置操作符,用于申请动态内存的分配,并同时进行初始化操作。其实现会调用malloc,对于基本类型变量,它只是增加了一个cookie结构,比如需要new的对象大小是object_size,则事实上调用malloc的参数是object_size+cookie,这个cookie结构存放的信息包括对象大小,对象前后会包含两个用于检测内存溢出的变量,所有new申请的cookie块会链接成双向链表。对于自定义类型,new会先申请上述的大小空间,然后调用自定义类型的构造函数,对object所在空间进行构造。

delete只调用一次析构函数,delete[]会调用每个成员的析构函数

用new分配的内存用delete释放,用new[]分配的内存用delete[]释放

调用new[]之后,释放内存使用delete[],没有指定需要析构的对象的个数,自己设计编译器的话怎么实现operatordelete。就是申请内存时可以多分配几个字节用来存放对象个数,delete[]的时候可以先调整指针位置来获取这个值。《深入探索c++对象模型》中解决方法:为vec_new()所传回的每一个内存区块配置一个额外的word,然后把元素个数藏在这个word当中

补充:

局部静态变量:定义:在局部变量之前加上关键字static,局部变量就被定义成为一个局部静态变量。说明:1)内存中的位置:静态存储区2)初始化:未经初始化的局部静态变量会被程序自动初始化为0(自动对象的值是任意的,除非他被显示初始化)3)作用域:作用域仍为局部作用域,当定义它的函数或者语句块结束的时候,作用域随之结束。

classA{};intmain(){cout<

空类的实例大小就是类的大小,所以sizeof(a)=1字节,如果a是指针,则sizeof(a)就是指针的大小,即4字节。

classA{virtualFun(){}};intmain(){cout<

classA{staticinta;};intmain(){cout<

classA{inta;};intmain(){cout<

(#define是预处理命令,在预处理是执行简单的替换,不做正确性的检查typedef是在编译时处理的,它是在自己的作用域内给已经存在的类型一个别名

用引用作为返回值最大的好处就是在内存中不产生被返回值的副本。但是有以下的限制:1)不能返回局部变量的引用。因为函数返回以后局部变量就会被销毁2)不能返回函数内部new分配的内存的引用。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memoryleak3)可以返回类成员的引用,但是最好是const。因为如果其他对象可以获得该属性的非常量的引用,那么对该属性的单纯赋值就会破坏业务规则的完整性。

友元提供了不同类的成员函数之间、类的成员函数和一般函数之间进行数据共享的机制。通过友元,一个不同函数或者另一个类中的成员函数可以访问类中的私有成员和保护成员。友元的正确使用能提高程序的运行效率,但同时也破坏了类的封装性和数据的隐藏性,导致程序可维护性变差。

volatile的意思是“脆弱的”,表明它修饰的变量的值十分容易被改变,所以编译器就不会对这个变量进行优化(CPU的优化是让该变量存放到CPU寄存器而不是内存),进而提供稳定的访问。每次读取volatile的变量时,系统总是会从内存中读取这个变量,并且将它的值立刻保存。

STL中的sort是用快速排序和插入排序结合的方式实现的,stable_sort()是归并排序。

C++STL从广义来讲包括了三类:算法,容器和迭代器。

STL中的hash表就unordered_map。使用的是哈希进行实现(注意与map的区别)。它记录的键是元素的哈希值,通过对比元素的哈希值来确定元素的值。unordered_map的底层实现是hashtable,采用开链法(也就是用桶)来解决哈希冲突,默认的桶大小是10.

vector的复杂度查看:O(1)插入:O(N)删除:O(N)

list复杂度查看:O(N)插入:O(1)删除:O(1)

set,map的插入复杂度就是红黑树的插入复杂度,是log(N)。unordered_set,unordered_map的插入复杂度是常数,最坏是O(N).vector的插入复杂度是O(N),最坏的情况下(从头插入)就要对所有其他元素进行移动,或者扩容重新拷贝

对于序列式容器(如vector,deque),序列式容器就是数组式容器,删除当前的iterator会使后面所有元素的iterator都失效。这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。

对于关联容器(如map,set,multimap,multiset),删除当前的iterator,仅仅会使当前的iterator失效,只要在erase时,递增当前iterator即可。这是因为map之类的容器,使用了红黑树来实现,插入、删除一个结点不会对其他结点造成影响。

对于链表式容器(如list),删除当前的iterator,仅仅会使当前的iterator失效,这是因为list之类的容器,使用了链表来实现,插入、删除一个结点不会对其他结点造成影响。

在c++中,内存被分为五个区,分别是栈、堆、全局/局部静态存储区、常量存储区和代码区。

面向对象的三大特性是:封装,继承和多态。

C++的虚函数是实现多态的机制。它是通过虚函数表实现的,虚函数表是每个类中存放虚函数地址的指针数组,类的实例在调用函数时会在虚函数表中寻找函数地址进行调用,如果子类覆盖了父类的函数,则子类的虚函数表会指向子类实现的函数地址,否则指向父类的函数地址。一个类的所有实例都共享同一张虚函数表。

虚表指针放在类的开头。通过对虚表指针的解引用找到虚表。

如果多重继承和多继承的话,子类的虚函数表长什么样子?多重继承的情况下越是祖先的父类的虚函数更靠前,多继承的情况下越是靠近子类名称的类的虚函数在虚函数表中更靠前。

虚表是一个指针数组,其元素是虚函数的指针,每个元素对应一个虚函数的函数指针。需要指出的是,普通的函数即非虚函数,其调用并不需要经过虚表,所以虚表的元素并不包括普通函数的函数指针。虚表内的条目,即虚函数指针的赋值发生在编译器的编译阶段,也就是说在代码的编译阶段,虚表就可以构造出来了。

虚表是属于类的,而不是属于某个具体的对象,一个类只需要一个虚表即可。同一个类的所有对象都使用同一个虚表。

为了指定对象的虚表,对象内部包含一个虚表的指针,来指向自己所使用的虚表。为了让每个包含虚表的类的对象都拥有一个虚表指针,编译器在类中添加了一个指针,*__vptr,用来指向虚表。这样,当类的对象在创建时便拥有了这个指针,且这个指针的值会自动被设置为指向类的虚表。

上面指出,一个继承类的基类如果包含虚函数,那个这个继承类也有拥有自己的虚表,故这个继承类的对象也包含一个虚表指针,用来指向它的虚表。

对象的虚表指针用来指向自己所属类的虚表,虚表中的指针会指向其继承的最近的一个类的虚函数

浅拷贝就是将对象的指针进行简单的复制,原对象和副本指向的是相同的资源。

而深拷贝是新开辟一块空间,将原对象的资源复制到新的空间中,并返回该空间的地址。深拷贝可以避免重复释放和写冲突。例如使用浅拷贝的对象进行释放后,对原对象的释放会导致内存泄漏或程序崩溃。

对象复用指得是设计模式,对象可以采用不同的设计模式达到复用的目的,最常见的就是继承和组合模式了。

零拷贝指的是在进行操作时,避免CPU从一处存储拷贝到另一处存储。在Linux中,我们可以减少数据在内核空间和用户空间的来回拷贝实现,比如通过调用mmap()来代替read调用。

用程序调用mmap(),磁盘上的数据会通过DMA被拷贝的内核缓冲区,接着操作系统会把这段内核缓冲区与应用程序共享,这样就不需要把内核缓冲区的内容往用户空间拷贝。应用程序再调用write(),操作系统直接将内核缓冲区的内容拷贝到socket缓冲区中,这一切都发生在内核态,最后,socket缓冲区再把数据发到网卡去。

对象以值传递的方式传入函数参数

如voidfunc(Dogdog){};

对象以值传递的方式从函数返回

如Dogfunc(){Dogd;returnd;}

对象需要通过另外一个对象进行初始化

因为结构体的成员可以有不同的数据类型,所占的大小也不一样。同时,由于CPU读取数据是按块读取的,内存对齐可以使得CPU一次就可以将所需的数据读进来。

对齐规则:

几种原因:

避免方法:

C++中的智能指针有auto_ptr,shared_ptr,weak_ptr和unique_ptr。智能指针其实是将指针进行了封装,可以像普通指针一样进行使用,同时可以自行进行释放,避免忘记释放指针指向的内存地址造成内存泄漏。

内联函数在编译时展开,而宏在预编译时展开

在编译的时候,内联函数直接被嵌入到目标代码中去,而宏只是一个简单的文本替换。

内联函数可以进行诸如类型安全检查、语句是否正确等编译功能,宏不具有这样的功能。

宏不是函数,而inline是函数

宏在定义时要小心处理宏参数,一般用括号括起来,否则容易出现二义性。而内联函数不会出现二义性。

inline可以不展开,宏一定要展开。因为inline指示对编译器来说,只是一个建议,编译器可以选择忽略该建议,不对该函数进行展开。

宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器符号表中的简单替换,因此它不能进行参数有效性的检测,也就不能享受C++编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型,这样,它的使用就存在着一系列的隐患和局限性。

成员初始化列表就是在类或者结构体的构造函数中,在参数列表后以冒号开头,逗号进行分隔的一系列初始化字段。

classA{intid;stringname;FaceImageface;A(int&inputID,string&inputName,FaceImage&inputFace):id(inputID),name(inputName),face(inputFace){}//成员初始化列表};因为使用成员初始化列表进行初始化的话,会直接使用传入参数的拷贝构造函数进行初始化,省去了一次执行传入参数的默认构造函数的过程,否则会调用一次传入参数的默认构造函数。所以使用成员初始化列表效率会高一些。

另外,有三种情况是必须使用成员初始化列表进行初始化的:

函数的调用过程1)从栈空间分配存储空间2)从实参的存储空间复制值到形参栈空间3)进行运算形参在函数未调用之前都是没有分配存储空间的,在函数调用结束之后,形参弹出栈空间,清除形参空间。数组作为参数的函数调用方式是地址传递,形参和实参都指向相同的内存空间,调用完成后,形参指针被销毁,但是所指向的内存空间依然存在,不能也不会被销毁。当函数有多个返回值的时候,不能用普通的return的方式实现,需要通过传回地址的形式进行,即地址/指针传递。

四种强制类型转换操作符分别为:static_cast、dynamic_cast、const_cast、reinterpret_cast

特性与要点:

coredump是程序由于异常或者bug在运行时异常退出或者终止,在一定的条件下生成的一个叫做core的文件,这个core文件会记录程序在运行时的内存,寄存器状态,内存指针和函数堆栈信息等等。对这个文件进行分析可以定位到程序异常的时候对应的堆栈调用信息。

使用gdb命令对core文件进行调试gdb[可执行文件名][core文件名]

预处理、编译、汇编、链接

1)预处理:对预处理命令进行替换等预处理操作主要处理源代码文件中的以“#”开头的预编译指令。处理规则见下1、删除所有的#define,展开所有的宏定义。2、处理所有的条件预编译指令,如“#if”、“#endif”、“#ifdef”、“#elif”和“#else”。3、处理“#include”预编译指令,将文件内容替换到它的位置,这个过程是递归进行的,文件中包含其他文件。4、删除所有的注释,“//”和“/**/”。5、保留所有的#pragma编译器指令,编译器需要用到他们,如:#pragmaonce是为了防止有文件被重复引用。6、添加行号和文件标识,便于编译时编译器产生调试用的行号信息,和编译时产生编译错误或警告是能够显示行号。

2)编译:代码优化和生成汇编代码把预编译之后生成的xxx.i或xxx.ii文件,进行一系列词法分析、语法分析、语义分析及优化后,生成相应的汇编代码文件。1、词法分析:利用类似于“有限状态机”的算法,将源代码程序输入到扫描机中,将其中的字符序列分割成一系列的记号。2、语法分析:语法分析器对由扫描器产生的记号,进行语法分析,产生语法树。由语法分析器输出的语法树是一种以表达式为节点的树。3、语义分析:语法分析器只是完成了对表达式语法层面的分析,语义分析器则对表达式是否有意义进行判断,其分析的语义是静态语义——在编译期能分期的语义,相对应的动态语义是在运行期才能确定的语义。4、优化:源代码级别的一个优化过程。5、目标代码生成:由代码生成器将中间代码转换成目标机器代码,生成一系列的代码序列——汇编语言表示。6、目标代码优化:目标代码优化器对上述的目标机器代码进行优化:寻找合适的寻址方式、使用位移来替代乘法运算、删除多余的指令等。

3)汇编:将汇编代码转化为机器语言将汇编代码转变成机器可以执行的指令(机器码文件)。汇编器的汇编过程相对于编译器来说更简单,没有复杂的语法,也没有语义,更不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译过来,汇编过程有汇编器as完成。经汇编之后,产生目标文件(与可执行文件格式几乎一样)xxx.o(Windows下)、xxx.obj(Linux下)。

4)链接:将目标文件彼此链接起来将不同的源文件产生的目标文件进行链接,从而形成一个可以执行的程序。链接分为静态链接和动态链接:1、静态链接:函数和数据被编译进一个二进制文件。在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件。空间浪费:因为每个可执行程序中对所有需要的目标文件都要有一份副本,所以如果多个程序对同一个目标文件都有依赖,会出现同一个目标文件都在内存存在多个副本;更新困难:每当库函数的代码修改了,这个时候就需要重新进行编译链接形成可执行程序。运行速度快:但是静态链接的优点就是,在可执行程序中已经具备了所有执行程序所需要的任何东西,在执行的时候运行速度快。

2、动态链接:动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接一样把所有程序模块都链接成一个单独的可执行文件。共享库:就是即使需要每个程序都依赖同一个库,但是该库不会像静态链接那样在内存中存在多分,副本,而是这多个程序在执行时共享同一份副本;更新方便:更新时只需要替换原来的目标文件,而无需将所有的程序再重新链接一遍。当程序下一次运行时,新版本的目标文件会被自动加载到内存并且链接起来,程序就完成了升级的目标。性能损耗:因为把链接推迟到了程序运行时,所以每次执行程序都需要进行链接,所以性能会有一定损失。

编译:将源代码编译成若干模块;

链接:将编译后的模块和所需的库函数进行链接。链接包括三种形式:静态链接,装入时动态链接(将编译后的模块在链接时一边链接一边装入),运行时动态链接(在执行时才把需要的模块进行链接)

装入:将模块装入内存运行将进程装入内存时,通常使用分页技术,将内存分成固定大小的页,进程分为固定大小的块,加载时将进程的块装入页中,并使用页表记录。减少外部碎片。通常操作系统还会使用虚拟内存的技术将磁盘作为内存的扩充。

执行后将在输出窗口出未释放的指针的位置。

IGP(内部网关协议):是在一个自治网络内网关(主机和路由器)间交换路由信息的协议。路由信息能用于网间协议(IP)或者其它网络协议来说明路由传送是如何进行的。IGP协议包括RIP、OSPF、IS-IS、IGRP、EIGRP。

距离矢量路由协议:

链路状态路由协议

配置了链路状态路由协议的路由器可以获取所有其它路由器的信息来创建网络的“完整视图”(即拓扑结构)。并在拓扑结构中选择到达所有目的网络的最佳路径(链路状态路由协议是触发更新,就是说有变化时就更新)。链路状态协议适用于以下情形:(1)网络进行了分层设计,大型网络通常如此。(2)管理员对于网络中采用的链路状态路由协议非常熟悉。(3)网络对收敛速度的要求极高。

RIP:路由信息协议(RouteInformationProtocol)”的简写,主要传递路由信息,通过每隔30秒广播一次路由表,维护相邻路由器的位置关系,同时根据收到的路由表信息使用动态规划的方式计算自己的路由表信息。RIP是一个距离矢量路由协议,最大跳数为16跳,16跳以及超过16跳的网络则认为目标网络不可达。

ping通过ICMP协议来进行工作。ICMP:网络报文控制协议

校验和发送的数据包的二进制相加然后取反,目的是检验数据在传输过程中是否有变化。如果收到段的校验和有差错,TCP将丢弃这个报文段和不确认接收到此报文段。

确认应答+序列号TCP给发送的每一个数据包进行编号,接收方对数据包进行排序,把有序数据传递给应用层。

超时重传当TCP发出一个段后,会启动一个计时器,等待目的端口确认接收到这个报文段。如果不能及时收到一个接收确认,将重传这个报文段。

流量控制TCP连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许发送端发送接收端缓冲区能够接纳的数据。当接收方来不及处理发送方的数据时,能够提示发送方降低发送的速率,防止包丢失。TCP用的流量控制协议是可变大小的滑动窗口协议。接收方有即时窗口(滑动窗口rwnd),随ACK报文发送。

拥塞控制当网络拥塞时,减少数据的发送。发送方有拥塞窗口,随ACK报文发送。

定义:流量控制即让发送方发送速率不要过快,让接收方有来得及接收,可以通过TCP报文中的窗口大小字段来控制发送方的发送窗口不大于接收方发回的窗口大小,这样就可以实现流量控制

解决方法:为了解决这个问题,TCP为每一个连接设定一个持续计时器(persistencetimer),只要TCP的一方接收到了对方的零窗口通知,就会启动这个计时器,周期性的发送零窗口探测报文段,对方在确认这个报文时给出现在的窗口大小。(注意:TCP规定,即便是在零窗口状况下,也必须接收以下几种报文段:零窗口探测报文、确认段报文、携带紧急数据的报文段)。

在什么情况下会减慢拥塞窗口增长的速度

2.10.1.三次握手

2.10.2.四次挥手TCP断开连接一般都是一方主动,一方被动的。这里假设client主动,server被动

第一次挥手:当客户端没有数据要继续发送给服务器端时,会发送一个FIN报文,报文中包含FIN=1,seq=u,告诉server:“我已经没有数据要发给你了,但是你要是还想给我发数据的话,你就接着发,但是你得告诉我你收到我的关闭信息了”,然后进入FIN-WAIT-1状态**;

第二次挥手:服务器在在接受到以上报文后,会告诉客户端:“我收到你的FIN消息了,但是你等我发完的”。此时给client会回复一个ACK=1,seq=v,ack=u+1,的ACK报文。服务器进入CLOSE_WAIT状态。

第三次挥手:当server发完所有数据时,他会给client发送一个FIN报文,告诉client说“我传完数据了,现在要关闭连接了”,报文中包含:ACK=1,FIN=1,seq=w,ack=u+1。然后服务器端进入LAST-ACK状态。

2.10.4.TIME_WAIT的意义(为什么要等于2MSL)

黏包:因为TCP为了减少额外开销,采取的是流式传输,所以接收端在一次接收的时候有可能一次接收多个包。而TCP粘包就是发送方的若干个数据包到达接收方的时候粘成了一个包。多个包首尾相接,无法区分。

导致TCP粘包的原因有三方面:

避免黏包的措施:

-200-请求成功-301-资源(网页等)被永久转移到其它URL-404-请求的资源(网页等)不存在-500-内部服务器错误-400-请求无效-403-禁止访问

SSL是传输层的协议

注意:服务器第一次传给客户端的公钥其实是CA对网站信息进行加密的数字证书;

权威CA使用私钥将网站A的信息和消息摘要(签名S)进行加密打包形成数字证书。公钥给客户端。

网站A将自己的信息和数字证书发给客户端,客户端用CA的公钥对数字证书进行解密,得到签名S,与手动将网站的信息进行消息摘要得到的结果S*进行对比,如果签名一致就证明网站A可以信任。

进程通信的方式主要有六种:管道,信号量,消息队列,信号,共享内存,套接字

管道:

信号量:

信号量是一个计数器,可以用来控制多个进程对共享资源的访问。信号量只有等待和发送两种操作。等待(P(sv))就是将其值减一或者挂起进程,发送(V(sv))就是将其值加一或者将进程恢复运行。

信号:

信号是Linux系统中用于进程之间通信或操作的一种机制,信号可以在任何时候发送给某一进程,而无须知道该进程的状态。如果该进程并未处于执行状态,则该信号就由内核保存起来,直到该进程恢复执行并传递给他为止。如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。信号是开销最小的。

共享内存

共享内存允许两个或多个进程共享一个给定的存储区,这一段存储区可以被两个或两个以上的进程映射至自身的地址空间中,就像由malloc()分配的内存一样使用。一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程,通过一个简单的内存读取读出,从而实现了进程间的通信。共享内存的效率最高,缺点是没有提供同步机制,需要使用锁等其他机制进行同步。

消息队列:

消息队列就是一个消息的链表,是一系列保存在内核中消息的列表。用户进程可以向消息队列添加消息,也可以向消息队列读取消息。消息队列与管道通信相比,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,而是可以根据自定义条件接收特定类型的消息。可以把消息看做一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程可以从消息队列中读取消息。

套接字:

套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同设备及其间的进程通信。

先来先服务(FCFS):按照作业到达任务队列的顺序调度FCFS是非抢占式的,易于实现,效率不高,性能不好,有利于长作业(CPU繁忙)而不利于短作业(I/O繁忙)

协程和微线程是一个东西。大多数web服务跟互联网服务本质上大部分都是IO密集型服务,IO密集型服务的瓶颈不在CPU处理速度,而在于尽可能快速的完成高并发、多连接下的数据读写。以前有两种解决方案:多进程:存在频繁调度切换问题,同时还会存在每个进程资源不共享的问题,需要额外引入进程间通信机制来解决。多线程:高并发场景的大量IO等待会导致多线程被频繁挂起和切换,非常消耗系统资源,同时多线程访问共享资源存在竞争问题。此时协程出现了,协程Coroutines是一种比线程更加轻量级的微线程。类比一个进程可以拥有多个线程,一个线程也可以拥有多个协程。可以简单的把协程理解成子程序调用,每个子程序都可以在一个单独的协程内执行。

协程就是子程序在执行时中断并转去执行别的子程序,在适当的时候又返回来执行。这种子程序间的跳转不是函数调用,也不是多线程执行,所以省去了线程切换的开销,效率很高,并且不需要多线程间的锁机制,不会发生变量写冲突协程运行在线程之上,当一个协程执行完成后,可以选择主动让出,让另一个协程运行在当前线程之上。协程并没有增加线程数量,只是在线程的基础之上通过分时复用的方式运行多个协程,而且协程的切换在用户态完成,切换的代价比线程从用户态到内核态的代价小很多,一般在Python、Go中会涉及到协程的知识,尤其是现在高性能的脚本Go。

协程进行中断跳转时将函数的上下文存放在其他位置中,而不是存放在函数堆栈里,当处理完其他事情跳转回来的时候,取回上下文继续执行原来的函数。

fork基础知识:

fork:创建一个和当前进程映像一样的进程可以通过fork()系统调用:/#include/#includepid_tfork(void);成功调用fork()会创建一个新的进程,它几乎与调用fork()的进程一模一样,这两个进程都会继续运行。在子进程中,成功的fork()调用会返回0。在父进程中fork()返回子进程的pid。如果出现错误,fork()返回一个负值。最常见的fork()用法是创建一个新的进程,然后使用exec()载入二进制映像,替换当前进程的映像。这种情况下,派生(fork)了新的进程,而这个子进程会执行一个新的二进制可执行文件的映像。这种“派生加执行”的方式是很常见的。

vfork的基础知识:

补充知识点:写时复制

fork和vfork的区别:

线程之间通信的两个基本问题是互斥和同步。

条件变量是线程的另外一种有效同步机制。这些同步对象为线程提供了交互的场所(一个线程给另外的一个或者多个线程发送消息),我们指定在条件变量这个地方发生,一个线程用于修改这个变量使其满足其它线程继续往下执行的条件,其它线程则等待接收条件已经发生改变的信号。当条件变量同互斥锁一起使用时,条件变量允许线程以一种无竞争的方式等待任意条件的发生。

同步机制:

线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。

说说线程同步方式有哪些?(线程安全性)线程间的同步方式包括互斥锁、信号量、条件变量、读写锁:互斥锁:采用互斥对象机制,只有拥有互斥对象的线程才可以访问。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。信号量:计数器,允许多个线程同时访问同一个资源。条件变量:通过条件变量通知操作的方式来保持多线程同步。读写锁:读写锁与互斥量类似。但互斥量要么是锁住状态,要么就是不加锁状态。读写锁一次只允许一个线程写,但允许一次多个线程读,这样效率就比互斥锁要高。

-如何实现线程安全:保证线程安全以是否需要同步手段分类,分为同步方案和无需同步方案。

操作系统内存管理:总的来说,操作系统内存管理包括物理内存管理和虚拟内存管理。操作系统的内存管理包括物理内存管理和虚拟内存管理

物理内存管理:包括程序装入等概念、交换技术、连续分配管理方式和非连续分配管理方式(分页、分段、段页式)。虚拟内存管理:虚拟内存管理包括虚拟内存概念、请求分页管理方式、页面置换算法、页面分配策略、工作集和抖动。这个系列主要使用linux内存管理来具体说明。

交换技术

交换(swapping)技术在多个程序并发执行时,可以将暂时不能执行的程序(进程)送到外存中,从而获得空闲内存空间来装入新程序(进程),或读人保存在外存中而处于就绪状态的程序。交换单位为整个进程的地址空间。交换技术常用于多道程序系统或小型分时系统中,因为这些系统大多采用分区存储管理方式。与分区式存储管理配合使用又称作“对换”或“滚进/滚出”(roll-in/roll-out)。

地址空间:将源程序经过编译后得到的目标程序,存在于它所限定的地址范围内,这个范围称为地址空间。地址空间是逻辑地址的集合。

存储空间:指主存中一系列存储信息的物理单元的集合,这些单元的编号称为物理地址存储空间是物理地址的集合。

根据分配时所采用的基本单位不同,可将离散分配的管理方式分为以下三种:页式存储管理、段式存储管理和段页式存储管理。其中段页式存储管理是前两种结合的产物。

页式存储

基本原理:将程序的逻辑地址空间划分为固定大小的页(page),而物理内存划分为同样大小的页框(pageframe)。程序加载时,可将任意一页放人内存中任意一个页框,这些页框不必连续,从而实现了离散分配。在页式存储管理方式中地址结构由两部构成,前一部分是页号,后一部分为页内地址w(位移量)。优点:1)没有外碎片,每个内碎片不超过页大比前面所讨论的几种管理方式的最大进步是,2)一个程序不必连续存放。3)便于改变程序占用空间的大小(主要指随着程序运行,动态生成的数据增多,所要求的地址空间相应增长)。缺点是:要求程序全部装入内存,没有足够的内存,程序就不能执行。

页式管理地址变换:在页式系统中,指令所给出的地址分为两部分:逻辑页号和页内地址。原理:CPU中的内存管理单元(MMU)按逻辑页号通过查进程页表得到物理页框号,将物理页框号与页内地址相加形成物理地址(见图4-4)。逻辑页号,页内偏移地址->查进程页表,得物理页号->物理地址:

段式存储

基本原理:在段式存储管理中,将程序的地址空间划分为若干个段(segment),这样每个进程有一个二维的地址空间。在前面所介绍的动态分区分配方式中,系统为整个进程分配一个连续的内存空间。而在段式存储管理系统中,则为每个段分配一个连续的分区,而进程中的各个段可以不连续地存放在内存的不同分区中。程序加载时,操作系统为所有段分配其所需内存,这些段不必连续,物理内存的管理采用动态分区的管理方法。在为某个段分配物理内存时,可以采用首先适配法、下次适配法、最佳适配法等方法。优点是:没有内碎片,外碎片可以通过内存紧缩来消除;便于实现内存共享。缺点:与页式存储管理的缺点相同,进程必须全部装入内存。

数据结构:为了实现段式管理,操作系统需要如下的数据结构来实现进程的地址空间到物理内存空间的映射,并跟踪物理内存的使用情况,以便在装入新的段的时候,合理地分配内存空间。进程段表:描述组成进程地址空间的各段,可以是指向系统段表中表项的索引。每段有段基址(baseaddress),即段内地址。系统段表:系统所有占用段(已经分配的段)。空闲段表:内存中所有空闲段,可以结合到系统段表中。

段式管理地址变换:在段式管理系统中,整个进程的地址空间是二维的,即其逻辑地址由段号和段内地址两部分组成。为了完成进程逻辑地址到物理地址的映射,处理器会查找内存中的段表,由段号得到段的首地址,加上段内地址,得到实际的物理地址。

页式和段式管理区别

1、基础概念:

物理内存,真实存在的插在主板内存槽上的内存条的容量的大小.内存是由若干个存储单元组成的,每个存储单元有一个编号,这种编号可唯一标识一个存储单元,称为内存地址(或物理地址)。我们可以把内存看成一个从0字节一直到内存最大容量逐字节编号的存储单元数组,即每个存储单元与内存地址的编号相对应。

虚拟内存地址:就是每个进程可以直接寻址的地址空间,不受其他进程干扰。每个指令或数据单元都在这个虚拟空间中拥有确定的地址。虚拟内存:就是进程中的目标代码,数据等虚拟地址组成的虚拟空间。虚拟内存与物理内存的区别:虚拟内存就与物理内存相反,是指根据系统需要从硬盘虚拟地匀出来的内存空间,是一种计算机系统内存管理技术,属于计算机程序,而物理内存为硬件。因为有时候当你处理大的程序时候系统内存不够用,此时就会把硬盘当内存来使用,来交换数据做缓存区,不过物理内存的处理速度是虚拟内存的30倍以上。

逻辑地址:源程序经过汇编或编译后,形成目标代码,每个目标代码都是以0为基址顺序进行编址的,原来用符号名访问的单元用具体的数据——单元号取代。这样生成的目标程序占据一定的地址空间,称为作业的逻辑地址空间,简称逻辑空间。在逻辑空间中每条指令的地址和指令中要访问的操作数地址统称为逻辑地址。即应用程序中使用的地址。要经过寻址方式的计算或变换才得到内存中的物理地址。

线性地址:线性地址是逻辑地址到物理地址变换之间的中间层。程序代码会产生逻辑地址,或者说是段中的偏移地址,加上相应段的基地址就生成了一个线性地址。如果启用了分页机制,那么线性地址可以再经变换以产生一个物理地址。若没有启用分页机制,那么线性地址直接就是物理地址。跟逻辑地址类似,它也是一个不真实的地址,如果逻辑地址是对应的硬件平台段式管理转换前地址的话,那么线性地址则对应了硬件页式内存的转换前地址。CPU将一个虚拟内存空间中的地址转换为物理地址,需要进行两步:首先将给定一个逻辑地址(其实是段内偏移量=),CPU要利用其段式内存管理单元,先将为个逻辑地址转换成一个线程地址,再利用其页式内存管理单元,转换为最终物理地址。

3、地址映射:

**虚拟地址向线性地址的转换**:

**线性地址向物理地址的转换**:Linux的每个用户进程都可以访问4GB的线性地址空间,而实际的物理内存可能远远少于4GB.采用分页机制。Linux仅把可执行映像的一小部分装入物理内存。当需要访问未装入的页面时.系统产生一个缺页中断,把需要的页读入物理内存。

4、虚拟地址管理:

5、swap对换空间:

32位Linux系统的每个进程可以有4GB的虚拟内存空间.而且系统中还要同时存在多个进程,但是,事实上大多数计算机都没有这么多物理内存空间,当系统中的物理内存紧缺时.就需要利用对换空间把一部分未来可能不用的页面从物理内存中移到对换设备或对换文件中。Linux采用两种方式保存换出的页面:一种是利用整个块设备,如硬盘的一个分区.即对换设备,另一种是利用文件系统中固定长度的文件.即对换文件。它们统称为对换空间。

6、分页机制管理:

Linux使用分页管理机制来更加有效地利用物理内存.当创建一个进程时.仅仅把当前进程的一小部分真正装入内存.其余部分需要访问时.处理器产生一个页故障.由缺页中断服务程序根据缺页虚拟地址和出错码调用写拷贝函数do—wp—page、此地址所属的vma的vm—ops指向的nopage、do—swap—page.swap—in等函数将需要的页换入物理内存。

定义:现代操作系统通过虚拟内存技术来扩大物理内存,虚拟内存每一页都映射在物理内存或磁盘上所以虚拟内存会比物理内存大,程序里访问的是虚拟地址,当程序访问页映射在磁盘上时,就会发生缺页中断,调用中断处理程序将页载入物理内存。例如:32位Linux的每个用户进程都可以访问4GB的线性地址空间,而实际的物理内存可能远远少于4GB.采用分页机制,Linux仅把可执行映像的一小部分装入物理内存。当需要访问未装入的页面时.系统产生一个缺页中断,把需要的页读入物理内存。

缺页中断*:即指的是当应用程序试图访问已映射在虚拟地址空间中,但是并未被加载在物理内存中的一个分页时,产生一个页不存在的中断,需要操作系统将其调入物理内存后再进行访问。在这个时候,被内存映射的文件(映像)实际上成了一个分页交换文件。

缺页中断的次数中断次数=进程的物理块数+页面置换次数。缺页中断率=(缺页中断次数/总访问页数)

页面置换算法当发生缺页中断时,如果操作系统内存中没有空闲页面,则操作系统必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。而用来选择淘汰哪一页的规则叫做页面置换算法。

几种缺页中断算法(FIFO,LRU与LFU):

用到:哈希+双向链表

进程地址空间内有:

一个程序在内存上有BSS段,Date段、text段三个组成的。在没有调入内存前,可执行程序分为代码段,数据区和未初始化数据三部分。

从操作系统层面上看,malloc是通过两个系统调用来实现的:brk和mmap

进程先通过这两个系统调用获取或者扩大进程的虚拟内存,获得相应的虚拟地址,在访问这些虚拟地址的时候,通过缺页中断,让内核分配相应的物理内存,这样内存分配才算完成。

字节序是对象在内存中存储的方式,大端即为最高有效位在前面,小端即为最低有效位在前面。判断大小端的方法:使用一个union数据结构

产生的必要条件:

产生死锁的原因主要是:

死锁的恢复:

打破占有且申请:可以实行资源预先分配策略。即进程在运行前一次性地向系统申请它所需要的全部资源。如果某个进程所需的全部资源得不到满足,则不分配任何资源,此进程暂不运行。只有当系统能够满足当前进程的全部资源需求时,才一次性地将所申请的资源全部分配给该进程。

打破循环等待:实行资源有序分配策略。采用这种策略,即把资源事先分类编号,按号分配,使进程在申请,占用资源时不会形成环路。所有进程对资源的请求必须严格按资源序号递增的顺序提出。进程占用了小号资源,才能申请大号资源,就不会产生环路,从而预防了死锁。

安全序列:安全序列是指对当前申请资源的进程排出一个序列,保证按照这个序列分配资源完成进程,不会发生“酱油和醋”的尴尬问题。我们假设有进程P1,P2,.....Pn,则安全序列要求满足:Pi(1<=i<=n)需要资源<=剩余资源+分配给Pj(1<=j

实现mutex最重要的就是实现它的lock()方法和unlock()方法。我们保存一个全局变量flag,flag=1表明该锁已经锁住,flag=0表明锁没有锁住。实现lock()时,使用一个while循环不断检测flag是否等于1,如果等于1就一直循环。然后将flag设置为1;unlock()方法就将flag置为0;

staticintflag=0;voidlock(){while(TestAndSet(&flag,1)==1);//flag=1;}voidunlock(){flag=0;}//因为while有可能被重入,所以可以用TestandSet()方法。intTestAndSet(int*ptr,intnew){intold=*ptr;*ptr=new;returnold;}3.5、互斥锁和读写锁区别互斥锁:mutex,用于保证在任何时刻,都只能有一个线程访问该对象。当获取锁操作失败时,线程会进入睡眠,等待锁释放时被唤醒。

读写锁:rwlock,分为读锁和写锁。处于读操作时,可以允许多个线程同时获得读操作。但是同一时刻只能有一个线程可以获得写锁。其它获取写锁失败的线程都会进入睡眠状态,直到写锁释放时被唤醒。注意:写锁会阻塞其它读写锁。当有一个线程获得写锁在写时,读锁也不能被其它线程获取;写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)。适用于读取数据的频率远远大于写数据的频率的场合。

互斥锁:mutex,用于保证在任何时刻,都只能有一个线程访问该对象。当获取锁操作失败时,线程会进入睡眠,等待锁释放时被唤醒

RCU:即read-copy-update,在修改数据时,首先需要读取数据,然后生成一个副本,对副本进行修改。修改完成后,再将老数据update成新的数据。使用RCU时,读者几乎不需要同步开销,既不需要获得锁,也不使用原子指令,不会导致锁竞争,因此就不用考虑死锁问题了。而对于写者的同步开销较大,它需要复制被修改的数据,还必须使用锁机制同步并行其它写者的修改操作。在有大量读操作,少量写操作的情况下效率非常高。

应用数据和静态资源分离将静态资源(图片,视频,js,css等)单独保存到专门的静态资源服务器中,在客户端访问的时候从静态资源服务器中返回静态资源,从主服务器中返回应用数据。

客户端缓存因为效率最高,消耗资源最小的就是纯静态的html页面,所以可以把网站上的页面尽可能用静态的来实现,在页面过期或者有数据更新之后再将页面重新缓存。或者先生成静态页面,然后用ajax异步请求获取动态数据。

集群和分布式(集群是所有的服务器都有相同的功能,请求哪台都可以,主要起分流作用)(分布式是将不同的业务放到不同的服务器中,处理一个请求可能需要使用到多台服务器,起到加快请求处理的速度。)可以使用服务器集群和分布式架构,使得原本属于一个服务器的计算压力分散到多个服务器上。同时加快请求处理的速度。

反向代理在访问服务器的时候,服务器通过别的服务器获取资源或结果返回给客户端。

数据库的索引类型可以分为逻辑分类和物理分类

逻辑分类:

物理分类

事务是一组逻辑操作的集合。实现事务就是要保证可靠性和并发隔离(ACID)。这些主要靠日志恢复和并发控制完成的。

日志恢复:数据库里有两个日志,一个是redolog,一个是undolog。redolog记录的是已经成功提交的事务操作信息,用来恢复数据,保证事务的持久性。undolog记录的是事务修改之前的数据信息,用来回滚数据,保证事务的原子性。

数据库事务是指逻辑上对数据的一种操作,这个事务要么全部成功,要么全部失败

以MySQL为例

一般的数据库都会支持并发操作,在并发操作中为了避免数据冲突,所以需要对数据上锁,乐观锁和悲观锁就是两种不同的上锁方式。

悲观锁假设数据在并发操作中一定会发生冲突,所以在数据开始读取的时候就把数据锁住。而乐观锁则假设数据一般情况下不会发生冲突,所以在数据提交更新的时候,才会检测数据是否有冲突。

悲观锁的实现:悲观锁有行级锁和页级锁两种形式。行级锁对正在使用的单条数据进行锁定,事务完成后释放该行数据,而页级锁则对整张表进行锁定,事务正在对该表进行访问的时候不允许其他事务并行访问。悲观锁要求在整个过程中一直与数据库有一条连接,因为上一个事务完成后才能让下一个事务执行,这个过程是串行的。

乐观锁有三种常用的实现形式:

对红黑树的理解:通过特殊的要求实现了比较奇怪的结构(数据存放方式),这种结构(存放方式)可以让查找数据变得特别有效,查找方式和常规的二叉查找树查找同。红黑树是在AVL树的基础上发展而来的。红黑树是一种二叉查找树,但在每个节点增加一个存储位表示节点的颜色,可以是红或黑(非红即黑)。通过对任何一条从根到叶子的路径上各个节点着色的方式的限制,红黑树确保没有一条路径会比其它路径长出两倍,因此,红黑树是一种弱平衡二叉树,相对于要求严格的AVL树来说,它的旋转次数少,所以对于搜索,插入,删除操作较多的情况下,通常使用红黑树。

红黑树较AVL树的优点:AVL树是高度平衡的,频繁的插入和删除,会引起频繁的rebalance,导致效率下降;红黑树不是高度平衡的,算是一种折中,插入最多两次旋转,删除最多三次旋转。所以红黑树在查找,插入删除的性能都是O(logn),且性能稳定,所以STL里面很多结构包括map底层实现都是使用的红黑树。

红黑树旋转:旋转:红黑树的旋转是一种能保持二叉搜索树性质的搜索树局部操作。有左旋和右旋两种旋转,通过改变树中某些结点的颜色以及指针结构来保持对红黑树进行插入和删除操作后的红黑性质。左旋:对某个结点x做左旋操作时,假设其右孩子为y而不是T.nil:以x到y的链为“支轴”进行。使y成为该子树新的根结点,x成为y的左孩子,y的左孩子成为x的右孩子。右旋:对某个结点x做右旋操作时,假设其左孩子为y而不是T.nil:以x到y的链为“支轴”进行。使y成为该子树新的根结点,x成为y的右孩子,y的右孩子成为x的左孩子。

B+是一种多路搜索树,主要为磁盘或其他直接存取辅助设备而设计的一种平衡查找树,在B+树中,每个节点的可以有多个孩子,并且按照关键字大小有序排列。所有记录节点都是按照键值的大小顺序存放在同一层的叶节点中。相比B树,其具有以下几个特点:

Epoll是Linux进行IO多路复用的一种方式,用于在一个线程里监听多个IO源,在IO源可用的时候返回并进行操作。它的特点是基于事件驱动,性能很高。epoll将文件描述符拷贝到内核空间后使用红黑树进行维护,同时向内核注册每个文件描述符的回调函数,当某个文件描述符可读可写的时候,将这个文件描述符加入到就绪链表里,并唤起进程,返回就绪链表到用户空间,由用户程序进行处理。Epoll有三个系统调用:epoll_create(),epoll_ctl()和epoll_wait()。

epoll提供了三个函数,epoll_create、epoll_ctl和epoll_wait。首先创建一个epoll对象,然后使用epoll_ctl对这个对象进行操作(添加、删除、修改),把需要监控的描述符加进去,这些描述符将会以epoll_event结构体的形式组成一颗红黑树,接着阻塞在epoll_wait,进入大循环,当某个fd上有事件发生时,内核将会把其对应的结构体放入一个链表中,返回有事件发生的链表。

缺点:1、大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。

epoll的优点:1、没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口);2、效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;即Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll。3、内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递;即epoll使用mmap减少复制开销。

用简单的话来定义tcpdump,就是:dumpthetrafficonanetwork,根据使用者的定义对网络上的数据包进行截获的包分析工具。tcpdump可以将网络中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助你去掉无用的信息。

THE END
1.软件开发需要学习哪些东西,小编今天为大家整理如下主要经营:数字藏品系统开发,元宇宙系统开发,嗨购模式,广告电商系统,泰山众筹模式,分享购cps系统、定制开发、请联系18002820787模式快速开发.APP软件系统公众号小程序开发APP软件系统公众号小程序开发APP软件系统公众号小程序开发APP软件系统公众号小程序开发APP软件系统公众号小程序开发公司以小程序开发、微商城开发、网站建设https://product.11467.com/info/20852241.htm
2.软件开发需要学什么在软件开发中,Web技术是必不可少的一部分 。无论你是想做前端还是后端开发,掌握这些基础知识都是非常重要的 。我发现,理解网页的结构和样式能让我们更好地进行开发和设计 。1 网页基础 :HTML和CSS是构建网页的基石 ?。我记得刚开始学的时候,总是搞不清楚这两者的区别 。HTMLhttps://baijiahao.baidu.com/s?id=1812626705699659631&wfr=spider&for=pc
3.自学软件开发步骤:开发软件需要学习什么?软件开发好不好学,软件开发需要学什么?软件开发是需要有一些天赋的,尤其是对于编程代码来说确实不太容易,可以选择自己喜比较喜欢的一门编程语言,比如说c语言,这些都是可以进行选择的。然后再进一步学习其他的软件编程语言,还有后台框架这一类的,要专攻一门。 http://www.apppark.cn/t-37110.html
4.c++后台开发需要掌握哪些知识c后端开发需要学什么文章浏览阅读6.4k次。出自知乎https://www.zhihu.com/question/34574154?sort=created_c 后端开发需要学什么https://blog.csdn.net/Joffer_Pong/article/details/76982726
5.学python能做什么类型的工作Python教程学python能做什么类型的工作 python 可用于各种类型的工作,包括:后台开发数据科学和分析机器学习和人工智能web 开发桌面应用程序开发脚本编写和自动化金融科学计算和建模教育和研究 Python 能做什么类型的工作 Python 是一种用途广泛的高级编程语言,拥有广泛的应用领域,可用于各种类型的工作。https://m.php.cn/faq/727935.html
6.后台开发入门:新手必读教程本文详细介绍了后台开发入门的各个方面,包括后端开发的基础概念、常用技术栈、开发环境搭建、第一个后端项目的创建以及常用开发框架的使用。文章旨在帮助新手快速掌握后台开发入门知识,深入了解后台开发。 后台开发入门:新手必读教程 后端开发基础概念 什么是后端开发 后端开发是指负责处理服务器端逻辑与数据交互的软件开https://www.imooc.com/article/357464
7.Web后端开发技术方面要学什么爱问知识人web后台开发需要学习的知识有HTML、CSS、JavaScript、DOM、Web服务器、服务器脚本语言、数据库及SQL语言https://iask.sina.com.cn/b/new2J4Rfh7is71.html
8.java后台开发要学黑盒和白盒测试吗java白盒测试编写测试代码java后台开发要学黑盒和白盒测试吗 java白盒测试编写测试代码,Junit单元测试:测试分类:黑盒测试:不需要写代码,给输入值,看程序是否能输出期望的值。白盒测试:需要写代码。关注程序具体的执行流程Junit使用:白盒测试步骤-1.定义一个测试类(测试用例)测试类名:被测https://blog.51cto.com/u_12868/11261538
9.Java开发全栈知识体系架构学习(服务器微服务数据库思维导2021年从入门到精通java开发全栈知识体系架构学习总结知识脑图(学习使用于项目实战)前端、后台、服务器、Linux、性能优化、集群搭建、微服务、大数据、项目实战等内容 Java JVM sql优化 springMVC spring cloud 作者其他创作 大纲/内容一、前端技术篇 1、基础知识篇 HTML CSS 去除a标签默认样式 分支主题 https://www.processon.com/view/60504b5ff346fb348a93b4fa
10.后台开发工资待遇(招聘要求,就业前景)后台开发需要什么学历?初中占0.1%,大专占9.3%……想知道其他学历占比多少,请点击查看 按学历统计 大专 ¥12.5K 本科 硕士 博士 初中 说明:薪资一般与学历正相关,一般学历越高,工资越高。后台开发工资按学历统计,大专工资¥12.5K,想知道其他学历工资,请点击查看招聘https://www.jobui.com/salary/quanguo-houtaikaifa/
11.人类高质量Java学习路线一条龙版开发框架是后台开发工作中不可或缺的,也是面试考察的重点,一定要好好学! 不知道 Java 能做什么的朋友们,学完开发框架,就会有答案啦。 下面给大家推荐的都是企业中应用最多的主流开发框架,知识点比较零碎,就放在一起讲了。 知识 Java Web 描述:Java 网页应用开发基础 https://xie.infoq.cn/article/a9fd4615c281e8ca41840ce37
12.11种类型的开发工程师(你会是哪一种?)后台开发工程师可以期望与负责网站面向客户方面的团队成员合作。服务器端开发也可以包括创建应用程序接口(API),以支持前端服务,而不需要双方的紧密耦合。 如果所有这些听起来都是你喜欢的工作,你可能会对典型的后端开发工程师的工资感兴趣。 3. 全栈网络开发工程师 https://www.wbolt.com/types-of-developers.html
13.java开发需要学什么学习java是一件枯燥的事,如果你想要学java就应该静下心来学,也要付出一点努力,毕竟java是一门热门的编程语言,前景很好。那么下面小编给大家说说java开发需要学什么,希望能对你有所帮助。 1、 java语法。 通过任何一本Java入门书籍,都可以学会Java的基本语法。千万不要认为,你把书上的例子程序都能写出来就算学会了https://www.qinxue365.com/jsjzx/380989.html
14.对于云原生时代的后端业务开发和项目系统学习,选GoOrJava?缺点:开发门槛高、入手慢、理解起来较难、效率低 就职方向:嵌入式开发、物联网硬件、硬件驱动器 C++:优势、缺点、就职方向 优势:兼顾性能和大型软件的开发效率,主流后台服务器的开发语言(腾讯为代表的大厂) 缺点:入门门槛高、精通较难 就职方向:后台服务器、电脑客户端、后台开发、交易系统开发、游戏等 https://developer.aliyun.com/article/1136265