2021-03-01 字节后端一面

1.GRPC跟HTTP的区别?

与HTTP(Restful API)对比,gRPC的优势
gRPC和restful API都提供了一套通信机制,用于server/client模型通信,而且它们都使用http作为底层的传输协议(严格地说, gRPC使用的http2.0,而restful api则不一定)。不过gRPC还是有些特有的优势,如下:

  1. gRPC可以通过protobuf来定义接口,可以有更加严格的接口约束条件,支持多种语言。
  2. protobuf可以将数据序列化为二进制编码,这会大幅减少需要传输的数据量,从而大幅提高传输速度。
  3. gRPC可以支持streaming流式通信(http2.0),提高传输速度。

Protobuf:

Protobuf 实际是一套类似Json或者XML的数据传输格式和规范,用于不同应用或进程之间进行通信时使用。相比较而言,Protobuf有如下优点:

  1. 足够简单
  2. 序列化后体积很小:消息大小只需要XML的1/10 ~ 1/3
  3. 解析速度快:解析速度比XML快20 ~ 100倍
  4. 多语言支持
  5. 更好的兼容性,Protobuf设计的一个原则就是要能够很好的支持向下或向上兼容

与HTTP(Restful API)对比,gRPC的优势

HTTP1.0和HTTP1.1的一些区别

HTTP1.0最早在网页中使用是在1996年,那个时候只是使用一些较为简单的网页上和网络请求上,而HTTP1.1则在1999年才开始广泛应用于现在的各大浏览器网络请求中,同时HTTP1.1也是当前使用最为广泛的HTTP协议。 主要区别主要体现在:

  1. 缓存处理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。

  2. 带宽优化及网络连接的使用,HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。

  3. 错误通知的管理,在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。

  4. Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。

  5. 长连接,HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。

HTTPS与HTTP的一些区别

  1. HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费。

  2. HTTP协议运行在TCP之上,所有传输的内容都是明文,HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输的内容都经过加密的。

  3. HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

  4. HTTPS可以有效的防止运营商劫持,解决了防劫持的一个大问题。

HTTP2.0和HTTP1.X相比的新特性

  1. 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。

  2. 多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。

  3. header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。

  4. 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。

https://www.cnblogs.com/heluan/p/8620312.html


2.C++11的智能指针介绍?

  1. unique_ptr实现独占式拥有或严格拥有概念,保证同一时间内只有一个智能指针可以指向该对象。它对于避免资源泄露(例如“以new创建对象后因为发生异常而忘记调用delete”)特别有用。另外unique_ptr还有更聪明的地方:当程序试图将一个 unique_ptr 赋值给另一个时,如果源 unique_ptr 是个临时右值,编译器允许这么做;如果源 unique_ptr 将存在一段时间,编译器将禁止这么做,比如:
unique_ptr<string> pu1(new string ("hello world"));
unique_ptr<string> pu2;
pu2 = pu1;                                      // #1 not allowed
unique_ptr<string> pu3;
pu3 = unique_ptr<string>(new string ("You"));   // #2 allowed

其中#1留下悬挂的unique_ptr(pu1),这可能导致危害。而#2不会留下悬挂的unique_ptr,因为它调用 unique_ptr 的构造函数,该构造函数创建的临时对象在其所有权让给 pu3 后就会被销毁。这种随情况而已的行为表明,unique_ptr 优于允许两种赋值的auto_ptr 。

注:如果确实想执行类似与#1的操作,要安全的重用这种指针,可给它赋新值。C++有一个标准库函数std::move(),让你能够将一个unique_ptr赋给另一个。例如:

unique_ptr<string> ps1, ps2;
ps1 = demo("hello");
ps2 = move(ps1);
ps1 = demo("alexia");
cout << *ps2 << *ps1 << endl;
  1. shared_ptr实现共享式拥有概念。多个智能指针可以指向相同对象,该对象和其相关资源会在“最后一个引用被销毁”时候释放。从名字share就可以看出了资源可以被多个指针共享,它使用计数机制来表明资源被几个指针共享。可以通过成员函数use_count()来查看资源的所有者个数。除了可以通过new来构造,还可以通过传入auto_ptr, unique_ptr,weak_ptr来构造。当我们调用release()时,当前指针会释放资源所有权,计数减一。当计数等于0时,资源会被释放。

成员函数:
use_count 返回引用计数的个数
unique 返回是否是独占所有权( use_count 为 1)
swap 交换两个 shared_ptr 对象(即交换所拥有的对象)
reset 放弃内部对象的所有权或拥有对象的变更, 会引起原有对象的引用计数的减少
get 返回内部对象(指针), 由于已经重载了()方法, 因此和直接使用对象是一样的.如 shared_ptr sp(new int(1)); sp 与 sp.get()是等价的

  1. weak_ptr 是一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的 shared_ptr. weak_ptr只是提供了对管理对象的一个访问手段。weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。它是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr。

https://www.nowcoder.com/tutorial/93/a34ed23d58b84da3a707c70371f59c21


3.智能指针存放在哪块内存空间?

shared_ptr的作用就是多个指针共享一个对象的生命周期,当所有指针都释放(或是不再指向对象)的时候,自动释放对象

智能指针的唯一作用,就是自动delete对象!注意,这一句话可以说明很多问题,其一,既然是要delete,那么这玩意首先必须是堆空间,所以如果你把栈空间、全局空间或者静态空间里变量的指针传给智能指针了,那么一定会出现奇怪的问题,因为对象在不该释放的时候被释放了,要不就是对象会重复释放,所以大家一定要注意,创建智能指针的时候,只能使用堆空间。其二,智能指针既然会自动delete对象,我们就不能再去手动delete对象了,否则,也会发生多次释放的问题。其三,也是比较深的一个坑,请先看下面例程:

int main(int argc, const char * argv[]) {
    
    
    auto p1 = new Test; // 划分堆空间
    std::shared_ptr<Test> sp(p1); // 创建智能指针
    std::shared_ptr<Test> sp2(p1); // 创建另一个智能指针
    
    return 0;
}

这段程序运行后,将会直接抛出异常。原因很简单,因为我们的sp和sp2都是用p1这个指针来创建的,他们彼此不知道对方的存在,所以,我们等于是用了两套引用计数的体系来管理了同一个对象,这其实和我们用智能指针来管理栈空间的效果是一样的,对象会被重复释放。所以大家在使用的时候一定要注意,同一个对象只能用同一套内存管理体系,如果它已经有智能指针了,那么再创建智能指针时,需要通过原来已有的指针创建,而不能重复用原始空间来创建。

为了避免这个问题,STL提供了一个函数,叫做make_shared,函数原型如下:

template <typename T, typename ...Args>
std::shared_ptr<T> std::make_shared(Args && ...args);

所以,我们希望大家在使用智能指针时,用make_shared函数来创建对象,而不要手动去new,这样就可以防止我们去使用原始指针创建多个引用计数体系。例程如下:

int main(int argc, const char * argv[]) {
    
    
    auto sp = std::make_shared<Test>(); // 创建智能指针
    auto sp2 = sp; // 创建另一个智能指针
    
    return 0;
}

https://blog.csdn.net/fl2011sx/article/details/103941346


4.weak_ptr = shared_ptr = new object()->计数为0了,shared_ptr是否会被析构?


5.虚表机制?虚表存放在哪块内存空间?是编译生成还是程序运行生成的?

C++对象的内存布局:
https://blog.csdn.net/caoshangpa/article/details/80112673


7.对象指针如何找到内存重对应的虚函数的?

C++类虚函数内存分布


8.golang的groutine的栈大小是多少?跟C++栈大小的区别?为什么?

Go 提供了一套简单且智能的协程管理,简单是因为协程在最开始的时候只有 2Kb 大小,智能是指协程的大小是能随着实际情况变大缩小的。

至于堆栈的大小,我们可以在 runtime/stack.go 找到以下注释:

需要注意,在不同的版本,有些设定是不一样的,比如:
Go 1.2 :协程的堆栈大小从 4Kb 增加到 8Kb。
Go 1.4 :协程的堆栈大小从 8Kb 减小到 2Kb。
堆栈的大小之所以改变是因为堆栈分配的策略改变了

https://studygolang.com/articles/28971


9.golang的groutine的栈大小是如何动态调整的?

Go: Goroutine 的堆栈大小是如何演进的


10.vector没有pop_front()

因为效率问题


11.golang的defer用法?for循环中的defer何时被触发?

测试程序:

package main

import "fmt"

func main() {
    
    
    fmt.Println("counting")

    for i := 0; i < 10; i++ {
    
    
        defer fmt.Println(i)
    }

    fmt.Println("done")
}

输出结果:

counting
done
9
8
7
6
5
4
3
2
1
0

猜你喜欢

转载自blog.csdn.net/weixin_43202635/article/details/114265089