【性能调优】JNI内存溢出案例(String对象溢出)

前言

场景:C++通过JNI将数据传输给Java程序

问题:运行一段时间String对象和Char字符不停变大,直到内存溢出(JVM-OOM)

1 过程

  • Jmap初步分析头部对象内存占用

PS:jmap -histo:live <pid>,执行该方法会同步执行一次GC,所以,展示的都是无法GC的对象。

发现:String对象有28万个,可能存在String对象被长期持有的现象,初步怀疑是HashMap等缓存持有

  • Jmap导出堆栈分析:导出堆栈时String对象是21万个
jmap -dump:live,format=b,file=/root/edr.bin 17994
  • 用eclipse-mat打开堆栈文件:通过Histogram看看对象实例数

发现:String对象确实是21万个

  • 看看String对象来自于哪里,并将String列表按RetainedHeap倒叙排列

发现:String对象是来自于本地JNI线程,且这个JNI线程还持有大量的内存

  • 查看程序线程内存占用情况

发现:存在10个相似的线程,都占用了很多内存,且线程类型还是守护类型,但是无法通过线程名判断是什么线程对象

  • 查看线程持有哪些对象

发现:线程持有14759个String对象,基本可以判断是该类(10个)线程没有将JNI-String内存释放

  • 最终确认确实是C++JNI相关代码没有释放内存

2 总结

  • 灵活应用对象持有和对象被引用关系,来分析内存
  • 线程名尽量按模块命名,不要使用默认命名(Thread-*),这样会减少问题定位的难度

爱家人,爱生活,爱设计,爱编程,拥抱精彩人生!

发布了96 篇原创文章 · 获赞 237 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qqchaozai/article/details/104044171