List如何排序
List排序可以通过实现Comparable接口并且实现compareTo方法,或者传入comparator去实现排序。
内存溢出/OOM是怎么回事?
内存溢出就是程序在运行的过程中,申请的内存超过了最大内存限制,导致JVM抛出OOM异常,这个叫内存溢出。
一般内存溢出有蛮多情况的,像是我之前的第一份实习不是要用java去做RPC自动化系统嘛。他本质就是java去做爬虫,所以自己私底下做过一些练习,然后就遇到了一个情况就是某个网页它指向的是下载某个文件,这个文件可能很大,就导致堆内存溢出。
我当时的解决方案是首先,通过它的url看下有没有特定的后缀,像是.doc之类的,如果是的话这个url就不加入处理的队列。其次就是通过httpURLConnectiongetContentLength()去加上限制,如果超过3MB,也是不把这个url加入处理的队列。
当然只能说规避了一小部分,首先就是很多url都没有像.doc这样显式的后缀的。其次就是很多HTT P Response其实都不设置contentLength的。
所以后续我记得还是手动设置了一个byte数组当作缓冲池,如果填满了这个数组而且还有未读完的数据的话,就放弃这个url。
那除了这种堆内存溢出之外的情况,还比较经常遇到的,可能写算法经常就可以看到栈溢出。就是循环递归没有写好之类的。
内存溢出如何排查和解决?
至于排查的话,这个项目是没有配普罗米修斯的,因为是我自己写的demo嘛。如果有配普罗米修斯的话会简单很多。那我们可以在启动项目的时候设置一下,当他内存溢出的时候保存一个内存快照,一个指定的dump文件。然后用分析工具,譬如MAT去执行分析。一般它会帮你分析最大的对象是谁,次大的对象是谁等等。然后就可以通过这个对象的路径,它是哪个包下面的,去定位到具体是哪段代码导致的内存溢出。
提到这个就得说一句,这也是为什么我们启动线程的时候最好命名的原因,像是如果没有命名的话,可能是公用线程池的一个线程,或者tomcat的线程,他在排查的时候就没有名字,只有数字序号之类的,排查起来就会麻烦一些。
那如果我们排查到是缓存没有做好的原因,那就去考虑一下缓存的过期时间是不是没有设置好,是不是可以放到redis里面之类的。从而去解决问题。
当然,其实我们应该内存达到60%左右就设置一下告警的。因为内存不断升高,在它溢出之前它肯定不断GC了,那GC的话又是很耗cpu的,就导致整个服务的响应都不是很好。最后内存溢出严重的话,整个服务应用可能都无响应了。甚至严重点的话,可能还会触发操作系统的内存溢出,然后终端进程也被kill掉了。
而且就是刚刚提到的,保存dump文件本身也是会占用cpu的,也会占用磁盘啊之类的,不过一般就是cpu。所以要尽量挑业务没有那么繁忙的时候。
内存升高的原因有很多啊,像是缓存使用不当、有很多突增的流量、或者内存泄漏都会导致内存升高,不及时处理的话就会导致内存溢出。
其实开发中经常碰到内存溢出的情况,特别是一开始整个服务的规模很小,没有多少日活的话,代码可能就写得比较简单,然后不想引入那么多中间件,可能缓存就随便做了,监控也没有。结果后来数据越来越多,然后别人或者说自己也忘了哪里写了个缓存了,就导致内存溢出了。然后只有一个日志去排查就很费劲。