Hello,今天给各位童鞋们分享的是JVM,赶紧拿出小本子记下来吧
一、内存溢出
内存溢出的原因:程序在申请内存时,没有足够的空间。
1. 栈溢出
方法死循环递归调用(StackOverflowError)、不断建立线程(OutOfMemoryError)。
2. 堆溢出
不断创建对象,分配对象大于最大堆的大小(OutOfMemoryError)。
3. 直接内存
JVM 分配的本地直接内存大小大于 JVM 的限制,可以通过-XX:MaxDirectMemorySize 来设置(不设置的话默认与堆内存最大值一样,也会出现OOM 异常)。
4. 方法区溢出
一个类要被垃圾收集器回收掉,判定条件是比较苛刻的,在经常动态生产大量 Class 的应用中,CGLIb 字节码增强,动态语言,大量 JSP(JSP 第一次运行需要编译成 Java 类),基于 OSGi 的应用(同一个类,被不同的加载器加载也会设为不同的类),都可能会导致OOM。
二、内存泄露
程序在申请内存后,无法释放已申请的内存空间,导致这一部分的原因主要是代码写的不合理,比如以下几种情况。
1. 长生命周期的对象持有短生命周期对象的引用
例如将 ArrayList 设置为静态变量,然后不断地向ArrayList中添加对象,则 ArrayList 容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。
2. 连接未关闭
如数据库连接、网络连接和 IO 连接等,只有连接被关闭后,垃圾回收器才会回收对应的对象。
3. 变量作用域不合理
例如:
一个变量的定义的作用范围大于其使用范围。
如果没有及时地把对象设置为 null。
4. 内部类持有外部类
Java 的 非静态内部类 的这种创建方式,会隐式地持有外部类的引用,而且默认情况下这个引用是强引用,因此,如果内部类的生命周期长于外部类的生命周期,程序很容易就产生内存泄露(可以理解为:垃圾回收器会回收掉外部类的实例,但由于内部类持有外部类的引用,导致垃圾回收器不能正常工作)。
解决办法:将非静态内部类改为 静态内部类,即加上 static 修饰,例如:
5. Hash值改变
在集合中,如果修改了对象中的那些参与计算哈希值的字段,会导致无法从集合中单独删除当前对象,造成内存泄露。
使用例子来说明。