朱晔《Java业务开发常见错误100例》课程学习整理
一、OOM
1.程序确实需要超出JVM配置的内存上限的内存。不管是程序实现的buhel,haishi因为各种框架对数据的重复处理、加工和转换,相同的数据在内存中不一定只只占一份空间。针对内存量使用超大的业务逻辑,比如缓存逻辑。文件上传下载和导出逻辑,我们在做容量评估时,可能还需要实际做一下Dump,
2.出现内存泄漏,也就是我们认为没有用的对象最终没有被GC,GC并不会回收强引用对象,当我们在程序中定义一些容器作为缓存,但容器中的数据无限增长,要特别注意最终会导致OOM。使用weakHashMap是解决这个问题的好办法,但如果强引用的Value有引用Key,也无法回收Entry
Java中引用类型和垃圾回收的关系
(1)垃圾回收不会回收有强引用的对象
(2)内存充足时,垃圾回收器不会回收具有软引用的对象
(3)垃圾回收器只要扫描到具有弱引用的对象就会回收,WeakHashMap就是利用这个特点
3.不合理的资源需求配置,在业务量小的时候可能不会出现问题,但业务量一大可能很快就会撑爆内存。比如,随意配置Tomcat的max-http-header-size参数,会导致一个请求使用过多的内存,请求量大的时候出现OOM。在进行参数配置的时候,我们要认识到,很多限制类参数限制的是背后资源的使用,资源始终是有限的,需要根据实际需求来合理设置参数。
例: 修改server.max-http-header = 10000000,会使得每一个请求对于Request和Response都占用20M内存,当在并发较多的情况下引起了OOM。
建议未生产系统的程序配置JVM参数启用详细的GC日志,方便观察垃圾
二、反射、注解和泛型遇到OOP
1.反射调用方法并不是通过调用时的传参确定方法重载,而是在获取方法的时候通过国方法名和参数类型来确定的。遇到方法有包装类型和基本类型重载的时候,需要特别注意
2.反射获取类成员,需要注意getXXX和getDeclaredXXX方法的区别,其中XXX包括Methods、Fields、Constructors、Annotations
3.泛型因为类型擦除会导致泛型方法T占位符被替换为Object,子类如果使用具体类型覆盖父类实现,编译器会生成桥接方法。这样既满足自雷方法重写父类方法的定义,又满足子类实现的方法有具体的类型。使用反射来获取方法清单时,需要特别注意。
4.自定义注解可以通过标记元注解@Inherited实现注解的继承,不过这只适用于类。如果要继承定义在接口或者方法上的注解,可以使用Spring工具类AnnotatedElementUtils,并注意getXXX方法和findXXX方法的区别