**问题:**一样一个Hello World程序,为何go的编译出来后,大小比C编译的大的多linux
由于C采用的是动态连接库形式编译,而go采用的是静态编译的形式,致使了编译后的二进制文件体积较大;windows
早期的计算机内存资源十分宝贵,才引入了动态装入的思想,也就产生了动态连接库;函数
如今的计算机内存动辄几十G,彻底不用为了节省几百k或者1M内存而大费周章;ui
go采用静态编译,不依赖任何动态连接库,能够避免各类动态连接库依赖的问题;spa
编译好后,只要平台是一致的(linux amd64),就能够任意部署,彻底不用考虑连接库依赖问题;插件
这是优势啊,居然有人吐槽编译后可执行文件体积太大?线程
在使用动态连接库的时候并不会把动态库的代码所有copy到生成的程序中,而是在程序运行的时候再去加载对应的代码,因此使用同一个动态库的程序能够共用一份代码,并且当你对动态库进行升级的时候,也不用去修改使用它的代码。code
同时,解决了相同的机器码在物理内存上存储多份的问题;进程
在物理内存上存放一份,哪一个进程须要能够将这个代码映射到本身的虚拟地址空间上;内存
并且随时能够升级动态连接库的内容,而不须要将已经运行的程序停下来;
也就是程序运行的时候本身占用必定的内存,加载动态连接库的时候将他载入到内存中,这两块内存没有半毛钱关系。只不过是程序将动态连接库的地址映射到本身的内存空间,以便调用罢了;
开一个线程检测dll,当发现有新版本时,先卸载旧的dll,而后加载新的;
go又是如何升级插件的呢?
p, err := plugin.Open("plugin1.so")
p, err := plugin.Open("plugin2.so")
定义一个全局变量,第二次open的时候覆盖第一次open就好了,下次调用就是新的函数了
当第二个so加载后,前面so的数据是没办法访问到,也就是说数据无法热更新(这时插件就不能用全局变量了)
//第一个插件不是还占着内存吗?等着被GC呗
//go的plugin只有打开模块和提取符号,没有关闭(卸载)
同一个so文件只能被打开一次
热更新只更新函数,不更新数据
//编译
go build -ldflags "-pluginpath=plugin1" -buildmode=plugin -o plugin1.so *.go
--ldflags里的-pluginpath的做用是: 每次编译的内部识别路径都是不一样的, 避免重复加载的警告
复制代码
linux下的动态连接库是.so,静态库是.a
windows下动态连接库是.dll
须要注意的是,目前go的动态连接库(plugin)只支持linux,windows下还无法使用。