OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Java、Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法 opencv采用C语言进行优化,而且,在多核机器上面,其运行速度会更快。它的一个目标是提供友好的机器视觉接口函数,从而使得复杂的机器视觉产品可以加速面世。

文件:url80.ctfile.com/f/25127180-739631245-c248ce?p=551685 (访问密码: 551685)

该库包含了横跨工业产品检测、医学图像处理、安防、用户界面、摄像头标定、三维成像、机器视觉等领域的超过500个接口函数。 同时,由于计算机视觉与机器学习密不可分,该库也包含了比较常用的一些机器学习算法。或许,很多人知道,图像识别、机器视觉在安防领域有所应用。但很少有人知道,在航拍图片、街道图片(例如google street view)中,要严重依赖于机器视觉的摄像头标定、图像融合等技术。 近年来,在入侵检测、特定目标跟踪、目标检测、人脸检测、人脸识别、人脸跟踪等领域,opencv可谓大显身手,而这些,仅仅是其应用的冰山一角。


这周有个朋友找到我,说他的程序出现了内存缓慢增长,没有回头的趋势,让我帮忙看下到底怎么回事,据朋友说这个问题已经困扰他快一周了,还是没能找到最终的问题,看样子这个问题比较刁钻,不管怎么说,先祭出 WinDbg。

二:WinDbg 分析

  1. 托管还是非托管泄露
    一直关注这个系列的朋友都知道,托管和非托管的排查是两个体系,分析方式完全不一样,所以要鉴定是哪一块的内存问题,首先要用 !address -summary 观察进程的 虚拟内存 布局。

0:000> !address -summary

— Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free 710 7d9320465000 ( 125.575 TB) 98.11% <unknown> 7547 2409bea8000 ( 2.252 TB) 92.87% 1.76%
Stack 33363 2c1fae0000 ( 176.495 GB) 7.11% 0.13% Heap 1179 0126d3000 ( 294.824 MB) 0.01% 0.00%
Image 2988 00c274000 ( 194.453 MB) 0.01% 0.00% TEB 11121 0056e2000 ( 86.883 MB) 0.00% 0.00%
Other 11 0001d9000 ( 1.848 MB) 0.00% 0.00% PEB 1 000001000 ( 4.000 kB) 0.00% 0.00%

— Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_MAPPED 7302 200071b1000 ( 2.000 TB) 82.47% 1.56% MEM_PRIVATE 45920 6ccc766000 ( 435.195 GB) 17.52% 0.33%
MEM_IMAGE 2988 0`0c274000 ( 194.453 MB) 0.01% 0.00%

— State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_FREE 710 7d9320465000 ( 125.575 TB) 98.11% MEM_RESERVE 12136 26c84ccf000 ( 2.424 TB) 99.94% 1.89%
MEM_COMMIT 44074 0`5aebc000 ( 1.421 GB) 0.06% 0.00%

从卦中看,当前进程的提交内存是 MEM_COMMIT= 1.4G, NT堆的内存占用是 Heap=294M,乍一看应该是托管内存泄露,接下来用 !eeheap -gc 观察托管堆。

0:000> !eeheap -gc
Number of GC Heaps: 12

Heap 0 (0000028577D73020)
generation 0 starts at 0x00000285B7000020
generation 1 starts at 0x00000285B6C00020
generation 2 starts at 0x0000028590800020
ephemeral segment allocation context: none

GC Allocated Heap Size: Size: 0x9598958 (156862808) bytes.
GC Committed Heap Size: Size: 0xea1c7e0 (245483488) bytes.

从卦中看很奇怪,托管堆也就 GC Committed Heap Size= 245M 的内存占用,说明问题不在托管堆上。

  1. 到底是哪里的泄露
    这就是本篇文章的亮点之处,毕竟没有按照以前的套路出牌,接下来问题在哪里呢? 还是得回头看下 虚拟内存布局,终于你会发现 Stack 处很奇怪,内存占用高达 TotalSize =176G, 内存段高达 RgnCount=3.3w,截图如下:

这两个蛛丝马迹已经告诉我们当前开启了非常多的线程,可以用 !address: -f:Stack 观察线程数和线程栈信息。

0:000> !address -f:Stack

    BaseAddress      EndAddress+1        RegionSize     Type       State                 Protect             Usage

  c0`80000000       c0`8104b000        0`0104b000 MEM_PRIVATE MEM_RESERVE                                    Stack      [~139; 323a8.320a4]c0`8104b000       c0`8104e000        0`00003000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE | PAGE_GUARD        Stack      [~139; 323a8.320a4]c0`8104e000       c0`81050000        0`00002000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE                     Stack      [~139; 323a8.320a4]c0`81050000       c0`8209b000        0`0104b000 MEM_PRIVATE MEM_RESERVE                                    Stack      [~140; 323a8.316b8]c0`8209b000       c0`8209e000        0`00003000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE | PAGE_GUARD        Stack      [~140; 323a8.316b8]c0`8209e000       c0`820a0000        0`00002000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE                     Stack      [~140; 323a8.316b8]...ed`460d0000       ed`4711b000        0`0104b000 MEM_PRIVATE MEM_RESERVE                                    Stack      [~11119; 323a8.8b20]ed`4711b000       ed`4711e000        0`00003000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE | PAGE_GUARD        Stack      [~11119; 323a8.8b20]ed`4711e000       ed`47120000        0`00002000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE                     Stack      [~11119; 323a8.8b20]ed`47120000       ed`4816b000        0`0104b000 MEM_PRIVATE MEM_RESERVE                                    Stack      [~11120; 323a8.9828]ed`4816b000       ed`4816e000        0`00003000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE | PAGE_GUARD        Stack      [~11120; 323a8.9828]ed`4816e000       ed`48170000        0`00002000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE                     Stack      [~11120; 323a8.9828]

从卦中看,当前线程高达 1.1w 个,有点吓人,终于算是找到源头了,

  1. 为什么会有 1w+ 的线程
    接下来就需要鉴定下这些线程是托管线程还是非托管线程,可以用 !t 观察。

0:000> !t
ThreadCount: 11104
UnstartedThread: 0
BackgroundThread: 11099
PendingThread: 0
DeadThread: 4
Hosted Runtime: no
Lock
DBG ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception
20 1 32588 0000028577D0DB30 202a020 Preemptive 0000000000000000:0000000000000000 0000028577529fc0 -00001 MTA
35 2 3262c 0000028577F3D000 2b220 Preemptive 00000285C0002660:00000285C0004008 0000028577529fc0 -00001 MTA (Finalizer)
36 4 326b4 0000028577F941B0 102b220 Preemptive 0000000000000000:0000000000000000 0000028577529fc0 -00001 MTA (Threadpool Worker)
37 5 31848 000002857811A420 202b220 Preemptive 0000000000000000:0000000000000000 0000028577529fc0 -00001 MTA

11116 11100 966c 000002C620A45300 202b220 Preemptive 00000285C86CB910:00000285C86CD868 0000028577529fc0 -00001 MTA
11117 11101 95b4 000002C61B928970 202b220 Preemptive 00000285996DF978:00000285996E18D0 0000028577529fc0 -00001 MTA
11118 11102 9630 000002C61B928FC0 202b220 Preemptive 00000285996E1978:00000285996E38D0 0000028577529fc0 -00001 MTA
11119 11103 8b20 000002C620A465F0 202b220 Preemptive 00000285B46B15C0:00000285B46B3518 0000028577529fc0 -00001 MTA
11120 11104 9828 000002C61E014CB0 202b220 Preemptive 00000285C86CD910:00000285C86CF868 0000028577529fc0 -00001 MTA

从卦中看: DBG 和 ID 的编号相差无几,说明是大多是托管线程,从后面的 MTA 来看,这是一个 new Thread 出来的线程,接下来试探看下它有没有 Name,我们拿 ThreadOBJ=000002C61E014CB0 来看吧。

0:000> dt coreclr!Thread 000002C61E014CB0

+0x1c0 m_ExposedObject : 0x00000285`7821d160 OBJECTHANDLE__

0:000> !do poi(0x00000285`7821d160)
Name: System.Threading.Thread
MethodTable: 00007ffa63844320
EEClass: 00007ffa6379af48
Tracked Type: false
Size: 72(0x48) bytes
File: D:\root\NewWF\System.Private.CoreLib.dll
Fields:
MT Field Offset Type VT Attr Value Name
00007ffa63a0d608 4000b0d 8 …ExecutionContext 0 instance 00000285c0acf930 _executionContext
00007ffa64cbaa78 4000b0e 10 …ronizationContext 0 instance 0000000000000000 _synchronizationContext
00007ffa637afd00 4000b0f 18 System.String 0 instance 0000028590888a78 _name

0:000> !DumpObj /d 0000028590888a78
Name: System.String
MethodTable: 00007ffa637afd00
EEClass: 00007ffa6379a6e0
Tracked Type: false
Size: 98(0x62) bytes
File: D:\root\NewWF\System.Private.CoreLib.dll
String: Console logger queue processing thread

经过抽检,发现线程名都是 Console logger queue processing thread,看样子和日志有关系,接下来使用 ~*e !clrstack 查看当前所有线程,发现线程都卡在 ConsoleLoggerProcessor.TryDequeue 上,截图如下:

看样子和微软的控制台日志组件有关系,下一步就要观察源码。

  1. 从源码中寻找答案
    导出源码后,利用 ILSpy 的代码回溯功能,发现是 ConsoleLoggerProcessor 类的构造函数 new 出来的线程,截图如下:

结合海量的重复线程栈,大概可以猜测到是代码将 Singleton 的模式改成了 Transient,导致不断的 new,不断的产生新的 Thread 去处理队列。

接下来我也懒得细究代码了,让朋友重点看一下 Microsoft.Extensions.Logging.Console 组件,朋友也很给力,终于找到了是 AppService 类在不断的 new 造成的,截图如下:

三: 总结
这次事故如果朋友有专业的 APM 监控,相信很快就能发现 Thread 爆高的问题,从 dump 中用内存来反推线程爆高,确实有一点出乎意料。

这个 dump 的教训是:理解 Singleton 和 Transient 的利弊,尽量遵循官方文档的写法吧。

Java+OpenCV实现图片中的人脸识别相关推荐

  1. Qt+OpenCV之图片中的人脸识别及人脸抠图

    效果 OpenCV函数知识点 imread() 功能:载入图像 函数原型:Mat cv::imread ( const String & filename, int flags = IMREA ...

  2. java+opencv+intellij idea实现人脸识别

    首先当然是需要安装opencv了,我用的是opencv2.4.13.下载完之后就可以直接安装了,安装过程也很简单,直接下一步下一步就好,我就不上图了. 接下来在opencv下找到jar包,比如我直接安 ...

  3. java学生管理系统(百度人脸识别 + Swing + mysql + 邮件发送 )

    文章目录 项目感受 项目历程和功能概述 具体实现 增删改查 音乐播放 背景更换 邮件发送 人脸识别 百度AI注册 人脸识别相关类的使用 单个参数的提取 使用opencv调用摄像头录入人脸 其他问题 总 ...

  4. java调用face_【AI】Java+Fileupload+JSTL+Face++实现人脸识别系统

    原标题:[AI]Java+Fileupload+JSTL+Face++实现人脸识别系统 一.前言 人工智能(Artificial Intelligence),英文缩写为AI.它是研究.开发用于模拟.延 ...

  5. JAVA 调用摄像头 拍照 实现人脸识别

    JAVA 调用摄像头 拍照 实现人脸识别 今天想试试百度的api 实现一下近年的热点,人脸识别,虽然咱不会,百度会呀,还免费给我无限用呀. 注册百度云账号等:略. Java中调用摄像头,网上搜到两种方 ...

  6. python读取视频流做人脸识别_基于OpenCV和Keras实现人脸识别系列——二、使用OpenCV通过摄像头捕获实时视频并探测人脸、准备人脸数据...

    基于OpenCV和Keras实现人脸识别系列手记: 项目完整代码参见Github仓库. 本篇是上面这一系列手记的第二篇. 在Opencv初接触,图片的基本操作这篇手记中,我介绍了一些图片的基本操作,而 ...

  7. 深度学习之基于opencv和CNN实现人脸识别

    这个项目在之前人工智能课设上做过,但是当时是划水用的别人的.最近自己实现了一下,基本功能可以实现,但是效果并不是很好.容易出现错误识别,或者更改了背景之后识别效果变差的现象.个人以为是数据选取的问题, ...

  8. Java后端 + 百度SDK实现人脸识别

    Java后端 + 百度SDK实现人脸识别 人工智能越来越贴近我们的生活,相信大家也经常接触到人脸识别,手机付款.app注册验证.门禁等等. 如果要用Java后台使用这些功能,那么需要怎么做呢?请看完下 ...

  9. 3d人脸识别算法opencv_用Opencv打造自己的人脸识别

    # 用Opencv打造自己的人脸识别 标签: opencv 人脸识别在现在使用的越来越多,所以使用opencv构造一个简单的人脸识别.步骤包括收集及处理数据,构建人脸识别器,进行人脸识别. 收集数据 ...

最新文章

  1. 计算勒让德多项式系数的第二种方法
  2. linux命令行终端全局反色
  3. 【若依(ruoyi)】表格实现tooltip
  4. js动态创建对象_JS深浅拷贝的深入浅出
  5. 【英语学习】【Level 08】U02 Movie Time L6 Blockbuster
  6. Introducing DataFrames in Apache Spark for Large Scale Data Science(中英双语)
  7. 学校校车运营各项安全管理制度_廊坊市加强校车安全管理 确保师生生命安全...
  8. 顶级前端工程师需要具备的经验和最佳实践(这才是市场急需的前端):
  9. 【渝粤教育】电大中专建筑材料 (4)作业 题库
  10. 非关系型数据库和关系型数据库区别(转载)
  11. php服务端搜索,功能改进
  12. java 相关学习资料汇总下载(全)
  13. 互联网医疗智能客服平台有什么优势
  14. 车载导航蓝牙知识介绍
  15. 英文字母或者中文字母文本替换
  16. How To JUST DO IT
  17. scratch3.0自定义logo
  18. 深度学习(计算机视觉)面试问题:
  19. 微软亚洲研究院的一道面试题
  20. wan端口未连接怎么弄_wan口未连接是什么意思?怎么解决

热门文章

  1. PaddleHub实战篇{ERNIE实现文新闻本分类、ERNIE3.0 实现序列标注}【四】
  2. 中国科学院大学计算机考研资料汇总
  3. 58同城2015校招笔试、一面、二面经历
  4. Java_输入圆的半径,计算周长及面积
  5. linux设置防火墙允许ftp通过,FTP服务器的防火墙通用设置规则
  6. 霍启刚晒全家出游照,网友们纷纷点赞,郭晶晶教育孩子有一套
  7. 如何让百度等搜索引擎搜到自己的博客
  8. python语言由psf组织所有、这是一个商业组织_智慧树知道营销管理章节测验答案...
  9. centos6.5(Linux)下搭建SVN服务器
  10. python kil 掉子进程