目录
虚拟机栈,每执行一个方法都会有一个栈帧入栈,栈帧中包含参数、局部变量、返回值地址等信息。如果代码层次太深,不断有方法入栈却没有出栈,Java虚拟机栈就会OOM。
保存类的基本信息,如果加载太多类就会 OOM
永久代的垃圾收集主要回收两部分内容:废弃常量和无用的类。
回收废弃常量与回收 Java 堆中的对象非常类似。以常量池中字面量的回收为例,假如一个字符串”abc”已经进入了常量池中,但是当前系统没有任何一个 String 对象是叫做”abc”的,也没有其他地方引用了这个字面量,如果这时发生内存回收,而且必要的话,这个”abc”常量就会被系统清理出常量池。常量池中的其他类(接口)、方法、字段的符号引用也与此类似。
注意:在大量使用反射、动态代理、CGLib 等 ByteCode 框架、动态生成 JSP 以及 OSGi这类频繁自定义 ClassLoader 的场景都需要虚拟机具备类卸载的功能,以保证永久代不会溢出。
堆中创建的对象过多就会触发GC,GC 的速度赶不上新建对象的速度也会发生 OOM。
注意:类需要同时满足下面 3 个条件才能算是“无用的类”
虚拟机可以对满足上述3 个条件的无用类进行回收,这里说的仅仅是“可以”,而并不是和对象一样,不使用了就必然会回收。
注意:方法区溢出方法区中只会产生OutOfMemoryError异常。
原因:
长生命周期对象持有短生命周期对象的引用可能会引起内存泄漏
HashMap、Vector等很容易出现内存泄漏, 集合被定义成静态的时候,由于它们的生命周期跟应用程序一样长 他们引用的所有对象Object不能被释放,如果将Object对象置为null,也还是会被Vector引用,可以将Vector对象置为null,切出对静态集合类的引用。
Vector vector = new Vector();
for (int i = 1; i<100; i++) {
Object object = new Object();
vector.add(object);
object = null;
}
//这样会造成内存泄漏
//...对vector的操作
//...与vector无关的其他操作这样会造成短暂的内存泄漏,method方法结束后被回收,
//...对vector的操作
vector = null;
//...与vector无关的其他操作
各种IO或者数据库连接时,最后都需要close()释放对象,这样也是长对象引用短对象,造成的内存泄漏。
SessionFactory factory = new SessionFactory();
try {Session session = factory.connect();
} finally{
session.close();
}
这里必须用close关闭连接,因为SessionFactory是长对象,session是短对象。
调用外部模块的时候,也应该注意防止内存泄漏。如模块A调用了外部模块B的一个方法,如:public void register(Object o)。这个方法有可能就使得A模块持有传入对象的引用,这时候需要查看B模块是否提供了去除引用的方法,如unregister()
使用单例模式的时候也有可能导致内存泄漏。因为单例对象初始化后将在JVM的整个生命周期内存在,如果它持有一个外部对象(生命周期比较短)的引用,那么这个外部对象就不能被回收,而导致内存泄漏。如果这个外部对象还持有其它对象的引用,那么内存泄漏会更严重
public class AppManager {
private static AppManager instance;
private Context context;
private AppManager(Context context) {
this.context = context;
}
public static AppManager getInstance(Context context) {
if (instance != null) {
instance = new AppManager(context);
}
return instance;
}
}
这是一个普通的单例模式,当创建这个单例的时候,由于需要传入一个Context,所以这个Context的生命周期的长短至关重要:
正确的方式应该改为下面这种方式:
public class AppManager {
private static AppManager instance;
private Context context;
private AppManager(Context context) {
// 使用Application 的context
this.context = context.getApplicationContext();
}
public static AppManager getInstance(Context context) {
if (instance != null) {
instance = new AppManager(context);
}
return instance;
}
}
或者这样写,连 Context 都不用传进来了: 在你的 Application 中添加一个静态方法,getContext() 返回 Application 的 context,
...
context = getApplicationContext();
...
//获取全局的context - - >return返回全局context对象
public static Context getContext(){
return context;
}
public classAppManager{
private static AppManager instance;
private Context context;
private AppManager() {
// 使用Application 的context
this.context = MyApplication.getContext();
}
public static AppManager getInstance() {
if (instance != null) {
instance = new AppManager();
}
return instance;
}
}
如何解决以及监控JVM内存、CPU的情况,请关注下篇文章。。。