您现在的位置是:首页 > 文章详情

【原创】编译 c++ gRPC 时遇到的坑……

日期:2021-10-28点击:953

由于项目需要,我要基于 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:本文敏感字如下,呵呵


更多精彩内容,欢迎关注我个人微信公众号

 

原文链接:https://my.oschina.net/moooofly/blog/5289742
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有1条评论来说两句吧...

优秀的个人博客,低调大师

2024 说:

make -j改成make -j4,make -j会尽可能的使用更多的进程同步编译

2024-04-07

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章