本文主要介绍Java虚拟机中的内存区域与各种内存溢出情况汇总。
数据区域
方法区、堆、虚拟机栈、程序计数器、本地方法栈
方法区
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码
运行时常量池:存放编译期生成的字面量和符号引用
异常(OutofMemoryError: PermGen space)产生原因:
1.往常量池中添加大量数据。eg:String.intern()
2.大量的类信息(或者动态代理)
异常处理:
适当增大配置:-XX:PermSize -XX:MaxPermSize
堆
存放对象实例
异常(OutofMemoryError)产生原因:
1.内存泄漏,最后导致内存溢出
2.代码创建过多对象导致超过设置的内存大小
异常处理(参考:http://blog.csdn.net/wisgood/article/details/16818243)
1.尽早释放无用对象的引用(好的办法是使用临时变量的时候,让引用变量在退出活动域后自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄露。)
2.程序进行字符串处理时,尽量避免使用String,而应使用StringBuffer(因为每一个String对象都会独立占用内存一块区域)
3.尽量少用静态变量(因为静态变量是全局的,GC不会回收)
4.避免集中创建对象尤其是大对象,如果可以的话尽量使用流操作
5. 尽量运用对象池技术以提高系统性能
6.不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象
7.优化配置:-Xms -Xmx
1. Q: Java中会存在内存泄漏吗?
A: Java中也存在内存泄露。当被分配的对象可达但已无用(未对作废数据内存单元的引用置null)即会引起。
如:
Java代码
Vector v=new Vector(10);
for (int i=1;i<100; i ) {
Object o=new Object();
v.add(o);
o=null;
}
// 此时,所有的Object对象都没有被释放,因为变量v引用这些对象。
// 对象加入到Vector后,还必须从Vector中删除,最简单释放方法就是将Vector对象设置为null。
2. Q: 内存泄露、溢出的异同?
A: 同:都会导致应用程序运行出现问题,性能下降或挂起。
B: 异:
1) 内存泄露是导致内存溢出的原因之一;内存泄露积累起来将导致内存溢出。
2) 内存泄露可以通过完善代码来避免;内存溢出可以通过调整配置来减少发生频率,但无法彻底避免。
虚拟机栈
存放基本数据类型,对象引用,操作数栈,动态链接,方法出口
异常原因:
(StackoverflowError)线程请求的栈深度大于虚拟结所允许的最大深度(eg:递归没有跳出)
(OutOfMemoryError)在扩展栈时无法申请到足够的内存空间
异常处理:
1.检查是否有递归没有正常结束代码
2.适当调整栈内存大小-Xss
程序计数器
当前线程所执行的字节码的行号指示器。(控制代码的执行顺序)
是一块较小的内存空间,没有规定任何OutOfMemoryError
本地方法栈
和虚拟机方法栈类似,只是负责Native方法
HotSpot将此栈与虚拟机栈合二为一。
异常同虚拟机栈异常。
-Xoss修改本地方法栈内存(但HotSpot此参数无效,通过设置-Xss来修改)
本机直接内存
不是虚拟机规范中的内存区域。NIO等一些处理直接使用的内存,可以使用Native函数库直接分配堆外内存,避免Java堆和Native堆中的来回复制数据,
异常现象:
在出现OutOfMemoryError后,Heap Dump 文件中,没有明显的异常,如果程序中又直接或间接的使用的NIO,就可以考虑检查是不是此内存溢出。
异常处理:
-XX:MaxDirectMemorySize