【原创】编译 c++ gRPC 时遇到的坑……
由于项目需要,我要基于 gRPC 开发一个通用的 wrapper ,前期已经将服务器侧相关的 gRPC 代码完成了集成,并基于 fake golang client 进行了功能测试,原以为生成 C/C++ gRPC 代码肯定是手到擒来的事情,没想到……居然“编译过程”本身成为了拦路虎。
按照 quickstart 文档的说明,可以使用的编译工具有如下三种
- cmake
- bazel(复杂,较高学习成本,且后续用不到)
- make(不推荐,人家说这个过时了)
既然如此,直接按照 cmake 的要求进行操作即可
# Choose a directory to hold locally installed packages.
$ export MY_INSTALL_DIR=$HOME/.local
$ mkdir -p $MY_INSTALL_DIR
$ export PATH="$MY_INSTALL_DIR/bin:$PATH"
# 安装高版本 cmake
$ wget -q -O cmake-linux.sh https://github.com/Kitware/CMake/releases/download/v3.19.6/cmake-3.19.6-Linux-x86_64.sh
$ sh cmake-linux.sh -- --skip-license --prefix=$MY_INSTALL_DIR
$ rm cmake-linux.sh
# Install the basic tools required to build gRPC
$ sudo apt install -y build-essential autoconf libtool pkg-config
结果……
0x01 困难一:公司网络环境下无法成功将相应内容下载到本地
这个命令其实隐含了很多外网下载内容,正常情况下很难下载完全,dddd
$ git clone --recurse-submodules -b v1.41.0 https://github.com/grpc/grpc
好在,我有国外 vps 可用,下载、打包,回传,一条龙解决问题
0x02 困难二:构建 c++gRPC 过程中对内存有相当高的要求
按照官方文档,只要执行如下命令,就可以得到需要的二进制程序了
# Build and install gRPC and Protocol Buffers
$ cd grpc
$ mkdir -p cmake/build
$ pushd cmake/build
$ cmake -DgRPC_INSTALL=ON \
-DgRPC_BUILD_TESTS=OFF \
-DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR \
../..
$ make -j
$ make install
$ popd
然而,实际执行时,你会发现……一般的机器根本就无法正常执行完成上述命令。
NOTE: 下文给出的是,成功编译过程中内存使用情况的记录(之前失败了无数次,浪费了大量时间)
经过无数次的调整,最终在一台内存资源相对充足(可用内存 30G),并开了 55G 的 swap 的机器上,成功解决了编译过程对内存量的“变态”需求(内存不足,会导致编译过程直接挂掉)
-
初始状态
-
执行
make -j后,可以发现内存占用开始飙升
-
当系统内存被耗光后,开始靠 swap 抗了……
-
编译进入“巅峰”状态时,总计占用了高达 55G 左右的内存量,而这在一般机器上是很难满足的(当然,在 4G 内存的机器上开 80G 的 swap ,理论上也能满足要求,但你会发现,整个编译过程会“快”的如蜗牛在爬行)
-
编译的后半程,系统内存和 swap 均被逐渐释放
-
最后,恢复到了正常水平
结论:要想成功编译出来 C++ gRPC 相关的东西,对编译机有非常高的要求(注:这里是严格按照官方命令进执行的,可能存在调整了一些参数后,相应要求会变低的可能,但我没有去验证这个猜想)
最后,提供一张由于内存不足,编译过程中被强行杀掉的现场图
0x03 困难三:vbox 虚拟盘大小只增不减问题
这个问题准确来说,是在解决第二个问题时出现的“衍生”问题。
问题是这样的:我的开发环境是在 vbox 虚拟机中创建的,最初分给该虚拟机的内存只有 2G,当我通过 make -j 编译时,很容易就会因为内存不足而被系统杀死,于是我第一时间就想到了通过创建 swap 缓解内存不足问题的手段。在创建了一个 10G 的 swap 分区重新编译后发现,依然会出现内存不足情况,于是继续增加 swap 大小,一路从 10G 调整到了 50G ,之后发现新的问题产生了,这时不再报内存不足的错误,而是 vbox 虚拟机直接挂掉了~~
简单排查后发现,居然是因为 vbox 所属物理机上对应分区的磁盘空间不足了,此时我第一反应是“不应该啊”,之前明明还有50G 左右的空间呢呀~~我靠……难道是……
是的,没错,开了 swap 之后,随着编译的进行,随着虚拟机内部对“内存”的疯狂占用,间接导致了物理机上的磁盘空间被“真实”的用光了
然而,从上面的编译过程来看,编译结束之后,内存占用会被完全释放掉的,那么物理机上被占用的空间能否被释放掉么?
此时,需要补充两个关于 vbox 虚拟机的知识点:
第一,vbox 虚拟盘的设定大小和实际占用大小在最初并不是一致的,而是在实际使用后,按需逐渐增大的
例如,这个由 vbox 默认创建的虚拟盘,“虚拟分配空间”大小为10G,但“实际分配空间”大小为 1.31G
另外一个虚拟盘是我最初规划时就为虚拟机额外挂载的、最大可达 100G 的虚拟盘;当我创建了 50G 的 swap ,并开始编译 c++ gRPC 之后,由于系统内存不足,触发了对 swap 的使用,最终该盘的“实际分配空间”逐渐增大到了 54.59G
第二,vbox 虚拟盘的“实际分配空间大小”只能增加不能减少,这也就意味着,虽然我是为了编译 c++ gRPC 临时分配了 50G 的 swap ,并且事后在虚拟机内部将其完全删除,但在物理机上看,该空间依然存在,且会一直存在了……
针对 vdi 格式的虚拟盘,网上能够找到的“攻略”都是教你如何“增大”的
软件界面上确实也直接告之了“存储空间缩减的功能尚未实现”
尝试了下“增大”功能,确实可以
最后,还剩下一个问题,由于“只增不减”的缘故,vbox 虚拟盘已经将我的 xx 盘几乎撑爆 ,仅剩下可怜的几十M空间,这个问题也得解决,要不然影响后续使用
常规操作,“复制粘贴”大法走起,确实解决了磁盘空间问题,但搬移后发现,虚拟机启动直接报错,大致意思是“找不到盘了”,嗯,合理,毕竟被移动了
于是,将原来挂的盘片删掉
再将搬移到新位置的盘片挂上……结果,又报错了,错误类似下图(原图当时没截取)
大致意思是,新挂上去的虚拟盘的 UUID 和原来已经注册过的虚拟盘的 UUID 相同,不允许挂;
具体解决办法可以参考如下链接文章,这里就不赘述了:
-
https://www.vdiskrecovery.com/blog/fix-virtualbox-cannot-register-hard-disk/
-
https://www.wintips.org/fix-virtualbox-failed-to-open-hard-disk-file-cannot-register-virtual-hard-disk-because-a-disk-with-the-same-uuid-already-exists/
最后的最后,终于成功的挂上了盘,终于再次成功的启动了我的开发机……
OK, 到这里,我只是解决了编译环境问题,真正的 c++ gRPC 代码的开发调试,还没开始呢……
PS:本文敏感字如下,呵呵
更多精彩内容,欢迎关注我个人微信公众号
















