0%

OOM问题解决

  • 先要找到问题是出在堆空间还是元空间,根据爆出来的异常信息就知道了,元空间爆出来的是java.lang.OutOfMemoryError:Metaspace,如果是堆内存不足则是java.lang.OutOfMemoryError:Java heap space
  • 使用 jstat -gcutil pid 5查看当前GC的状态
  • 使用jmap -histo:live pid统计存活对象的分布情况,从高到低查看占据内存最多的对象
  • 使用jmap -dump:live,format=b,file=heap.bin <pid> dump快照
  • 然后通过分析工具来对dump出来的快照进行分析,来看是内存泄漏还是内存溢出
  • 如果是内存泄漏,使用工具查看内存泄漏对象到GC Roots的引用链,找到泄漏对象是通过怎样的路径与GC Roots相关联并导致垃圾回收器无法自动回收,定位出泄漏代码的位置
  • 如果不是内存泄漏,那就说明内存中的对象都必须存活着,就只能适当的调虚拟机参数了(-Xms和-Xmx)
  • 在检查一下是不是有某些对象的生命周期过长(不必要的静态调整为非静态,方法外定义的看看可不可以移到方法内),尝试减少程序运行期的内存消耗

还有一种情况是 GC overhead limit exceeded,这是达到了GC的开销限制

满足下列所有条件时会抛出该错误

  • 花在Full GC上的时间超出了-XX:GCTimeLimit指定的时间,默认是98,也就是98%的时间花在了GC上
  • 一次Full GC回收的内存量少于-XX:GCHeapFreeLimit设置的值,默认是2,表示Full GC期间释放的内存不足堆的2%
  • 上面两个条件连续5次Full GC都满足
  • 设置了-XX:+UseGCOverheadLimit,默认设置

字节码文件

字节码文件中包含的内容有包含类的版本信息、字段、方法以及接口等描述信息外,还有常量池表(Constant Pool Table),包括各种字面量和对类型、域(Field)和方法的符号引用,指令代码行号表等信息

  • java栈中:局部变量表、操作数栈
  • java堆中
  • 常量池
  • 帧数据区、方法区的剩余情况

文件结构

u1、u2、u4、u8分别表示1个字节、2个字节、4个字节、8个字节的无符号数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ClassFile {
u4 magic;// 魔数,识别class文件格式 cafe babe
u2 minor_version; // 副版本号
u2 major_version; // 主版本号
u2 constant_pool_count; //常量池计数器,计数从1开始,记录常量池表中的数量,减一等于常量池表的长度
cp_info constant_pool[constant_pool_count-1]; //常量池表,用于存放编译时期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放
u2 access_flags; // 访问标识
u2 this_class; // 类索引,对应constant_pool表中的一个有效索引值
u2 super_class; // 父类索引,必须是0或者对应constant_pool表中的一个有效索引值
u2 interfaces_count; // 接口计数器,接口索引数量
u2 interfaces[interfaces_count]; // 接口索引集合
u2 fields_count; // 字段计数器,字段表字段数量
field_info fields[fields_count]; // 字段表
u2 methods_count; // 方法计数器,方法表方法数量
method_info methods[methods_count]; // 方法表
u2 attributes_count; // 属性计数器,属性表属性数量
attribute_info attributes[attributes_count]; //属性表
}
阅读全文 »

使用springSession完成分布式session

分布式session可以使用spring session来进行实现,由于HttpRequest的Wrapper功能,许多HttpRequest中的方法都可以进行替换来进行自定义的重写,可以在Wrapper中将getSession方法重写掉,然后进行自定义的session存储和处理,当然了,你能想到的,一般都是早就有人已经实现了,就不重复造轮子了

spring session已经实现出了上述功能,只需要进行配置就可以实现啦

这里演示的是将session存储在redis中,所需要的依赖

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>

<dependency>
<groupId>biz.paluch.redis</groupId>
<artifactId>lettuce</artifactId>
<version>3.4.2.Final</version>
</dependency>
阅读全文 »

方法区

方法区在逻辑上虽然属于堆的一部分,但是简单的实现上可能不会选择去进行垃圾回收或者进行压缩,在Hotspot中为了区分方法区和堆,方法区又被称为非堆,所以方法区可以看做是独立于堆的一块内存空间

方法区的生命周期与JVM实例也是一致的,在JVM启动的时候就会被创建,也是各个线程共享的区域,其存储的是已被虚拟机加载的类的信息、常量、静态变量、即时编译器编译后的代码等数据,所以方法区的大小决定了系统可以保存多少个类,如果系统定义的类过多,方法区就会溢出,从而出现OOM

jdk7及之前报的是java.lang.OutOfMemoryError:PermGen space,jdk8报的是java.lang.OutOfMemoryError:Metaspace

在jdk7中方法区被称为永久代(Permanent Space),在jdk8中方法区被称为元空间(MetaSpace)

永久代和元空间可以看做是方法区的实现

元空间

阅读全文 »

HandlerExceptionResolver异常处理

HandlerExceptionResolver是专门进行异常处理的,在render之前进行工作,从异常中解析出ModelAndView

1
2
3
4
5
6
public interface HandlerExceptionResolver {

ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);

}
  • DefaultHandlerExceptionResolver 根据不同类型的异常来进行解析,response.sendError设置不同的错误码

    1
    response.sendError(HttpServletResponse.SC_NOT_FOUND);
  • ExceptionHandlerExceptionResolver 使用@ExceptionHandler注解的方法来进行异常解析

  • ResponseStatusExceptionResolver 解析有@ResponseStatus注解的异常

  • SimpleMappingExceptionResolver 通过配置的异常类和View的映射关系来解析异常

阅读全文 »