.NET Core是从3.0开始才支持System.Drawing的,在3.0之前我们用的是一个叫SixLabors.ImageSharp.Drawing的第三方的库来实现.NET Core上的绘图。当我们的系统升级到.NET Core 3.1之后,我就抛弃掉了SixLabors.ImageSharp.Drawing,使用了微软官方的System.Drawing,一来可以减少一个依赖包,二来我认为官方的东西应该更稳定可靠,更关键的一点是SixLabors.ImageSharp.Drawing一直是beta版……
另外吐槽一下这个SixLabors.ImageSharp.Drawing,版本更迭中经常出现断层,使得升级它的版本常常需要改代码,不是什么好用的东西。
切到System.Drawing后,一切运行良好,已有一年多的时间。这里需要提到的一点就是,要在Linux下正常使用System.Drawing需要mono项目的libgdiplus,github地址是:https://github.com/mono/libgdiplus,而mono不算是微软官方的东西,这么看的话System.Drawing也不够官方啊。
而最近我们系统出问题了,程序直接崩溃,没有任何征兆,也无法预测,运行一两天就会出现。检查Linux的系统日志,发现如此:
Jan 22 13:22:58 l-test njt.fms[5839]: *** Error in `/usr/bin/dotnet': corrupted size vs. prev_size: 0x00007f4a80030c90 *** Jan 22 13:22:58 l-test njt.fms[5839]: ======= Backtrace: ========= Jan 22 13:22:58 l-test njt.fms[5839]: /lib64/libc.so.6(+0x7f3e4)[0x7f4d50cbc3e4] Jan 22 13:22:58 l-test njt.fms[5839]: /lib64/libc.so.6(+0x814db)[0x7f4d50cbe4db] Jan 22 13:22:58 l-test njt.fms[5839]: /lib64/libfontconfig.so.1(FcFontSetDestroy+0x42)[0x7f4a70a0d682] Jan 22 13:22:58 l-test njt.fms[5839]: /lib64/libgdiplus.so.0(+0x1448e)[0x7f4a7d00e48e] Jan 22 13:22:58 l-test njt.fms[5839]: /lib64/libgdiplus.so.0(GdipGetFontCollectionFamilyCount+0x36)[0x7f4a7d00eb56] Jan 22 13:22:58 l-test njt.fms[5839]: [0x7f4cdc6e0f09] Jan 22 13:22:58 l-test njt.fms[5839]: ======= Memory map: ======== Jan 22 13:22:58 l-test njt.fms[5839]: 00400000-00411000 r-xp 00000000 fd:01 1314605 /usr/share/dotnet/dotnet Jan 22 13:22:58 l-test njt.fms[5839]: 00610000-00611000 r--p 00010000 fd:01 1314605 /usr/share/dotnet/dotnet Jan 22 13:22:58 l-test njt.fms[5839]: 00611000-00612000 rw-p 00011000 fd:01 1314605 /usr/share/dotnet/dotnet Jan 22 13:22:58 l-test njt.fms[5839]: 010ef000-03022000 rw-p 00000000 00:00 0 [heap] Jan 22 13:22:58 l-test njt.fms[5839]: 7f4a68df6000-7f4a68df7000 ---p 00000000 00:00 0 Jan 22 13:22:58 l-test njt.fms[5839]: 7f4a68df7000-7f4a695f7000 rw-p 00000000 00:00 0 Jan 22 13:22:58 l-test njt.fms[5839]: 7f4a695f7000-7f4a695f8000 ---p 00000000 00:00 0 Jan 22 13:22:58 l-test njt.fms[5839]: 7f4a695f8000-7f4a69df8000 rw-p 00000000 00:00 0 Jan 22 13:22:58 l-test njt.fms[5839]: 7f4a69df8000-7f4a69df9000 ---p 00000000 00:00 0 Jan 22 13:22:58 l-test njt.fms[5839]: 7f4a69df9000-7f4a6a5f9000 rw-p 00000000 00:00 0 Jan 22 13:22:58 l-test njt.fms[5839]: 7f4a6a5f9000-7f4a6a609000 r-xp 00000000 fd:01 672887 /usr/lib64/libGLX.so.0.0.0 Jan 22 13:22:58 l-test njt.fms[5839]: 7f4a6a609000-7f4a6a809000 ---p 00010000 fd:01 672887 /usr/lib64/libGLX.so.0.0.0 Jan 22 13:22:58 l-test systemd[1]: njt.fms.service: main process exited, code=killed, status=6/ABRT Jan 22 13:22:58 l-test systemd[1]: Unit njt.fms.service entered failed state. Jan 22 13:22:58 l-test systemd[1]: njt.fms.service failed.
是libgdiplus出问题无疑了,但问题在于这个错误无法重现,程序跑一两天才会出现,我们的程序间接使用了“GdipGetFontCollectionFamilyCount”函数,参数并无不妥,要解决就比较麻烦了。只能寻找变通方案,难不成要切回SixLabors.ImageSharp.Drawing?——还真是,我找到了微软官方的一段说明:
地址:https://docs.microsoft.com/en-us/dotnet/api/system.drawing?view=dotnet-plat-ext-5.0
它竟然不建议我们在ASP.NET Core中使用System.Drawing,而是另外推荐了ImageSharp,之前的努力都白费了,究其原因就是操作系统图形接口上的鸿沟,System.Drawing是一套针对GDI+的接口,GDI即Windows原生的图形接口,GDI+是对GDI的增强,比如能在底层使用DirectDraw来加速图形绘制,支持渐变色渲染和一些动画效果等,这套接口是针对Windows的,要在别的系统中实现这么一套接口有些难,底层实现有太多不一样,甚至在没有图形界面的Windows(Windows Server Core了解一下)中估计都成问题,所以官方也不保证System.Drawing一定好用,但由于GDI+的使用惯性很大,也不能完全把它舍弃,再说在一般的Windows环境下,开发个桌面程序啥的它是一点问题都没有的。
我最后还是不得不把相关代码切回SixLabors.ImageSharp.Drawing,中间又改了不少东西,不算太难,但也有些工作量。