一次OOM记录

0x00 问题初现
公司一个C/S产品,使用的JavaFX进行开发,用户面板展示了一个罐的动态效果图,类似这种的:
在这里插入图片描述
高度波浪是动态的效果图,前端小哥整的GIF。
因为需要使用某一款只有32位驱动的读卡器所以jre也就选择使用32位的了,开发测试都正常进行中,有一天 测试同事说 他新加的罐不显示了,最多只能显示XX个,我心想不应该啊,不记得哪里设置了对显示数目的设置,赶紧去巴拉巴拉代码,也没发现限制显示的逻辑,在我机器上启动后,同样数量的罐也能正常显示。疑惑中猛然想起我机器上暂时不用读卡器所以切换到64位的jdk了,于是更改为32位后本地复现下这问题,果然报错了:
在这里插入图片描述
堆溢出了!!!

0X01 定位问题
堆栈异常信息提示是在GIFImageLoader2中加载gif时出现的异常,这时候基本有些感觉了,应该是堆分配不了更多的空间导致的溢出。可是我的gif图只有1M左右大小怎么会才显示几个罐就直接用完空间了呢?好吧,继续查!
在这里插入图片描述
jvisualvm 为了方便演示,在vm启动参数中加上 -Xmx200m
在这里插入图片描述
在加载gif动图前一直是30M左右,开始加载后,马上开始飙升,直接干到了上限处,然后就报了OOM异常。
问题很明显了,就是本来一个1M左右的gif加载渲染时却占用了将近50M的内存!32位jre默认最大的heapsize 是 700M左右,64位的是4G左右;现在问题的关键就是搞明白为什么 加载gif时内存用了50倍!
0x02 继续巴拉代码
一个gif图片只有不到1M的大小,既然是翻了50倍说明应该是有 多次加载或者循环加载的方法,根据异常信息快速定位过去:
在这里插入图片描述
这里只有在image==null的时候才会break出去,再往下:
在这里插入图片描述
waitForImageFrame的方法:
在这里插入图片描述
到了关键的地方了,显示每次遇到0x2c就会返回加载,只有遇到0x3B时才会返回-1 结束图片的加载,那么这俩是什么呢?
百度走起~~~
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

通过查看相关资料真相了,gif图片可以理解成是由多个图片根据某些压缩算法(比如LZW算法)合成的,而JavaFX在加载gif图时,是通过0X2C来一幅一幅的加载到ImageFrame ,遇到0x3B结束加载,然后才渲染的,可以理解成将图片解压缩了,然后一幅一幅的图片 通过Animation加载的,这就导致了本来是压缩的gif实际渲染时占用内存翻了很多倍。

0x03 解决办法
目前想到的最快的解决办法就是 减少gif中图片的数量,也就是减少 0x2c,尽快解决的话,直接ps打开:
在这里插入图片描述
这里也验证了上面渲染解压缩了的结论,可以通过删除中间一些变化小的桢图,加快动画速度的方式,对图片进行压缩。
再次验证,图片也都可以加载出来了,并且内存占用也大大的降低了。
在这里插入图片描述

0x04 扩展想法
这里JavaFX加载gif的方式明显是不合理的,当然因为现在也基本没多少人使用这个框架了,导致很少维护了。每次加载个压缩后不到1M 渲染却需要 count(0x2c) 数量的内存,这大大的浪费了空间。

接下来尝试下 使用不同的渲染方式,实现空间利用率的提升。
未完待续…

【参考文章】https://blog.csdn.net/linghu_java/article/details/14002413

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值