类加载器和内存异常
类加载器
主要过程
加载、链接(验证:确保被加载类的正确性;准备:为类的静态变量分配内存,并将其初始化为默认值;解析:把类中的符号引用转换为直接引用;),初始化(为静态常量赋值)
加载器
1)Bootstrap ClassLoader
负责加载JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包
3)App ClassLoader
负责加载classpath中指定的jar包及目录中class
4)Custom ClassLoader
属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader
JVM类加载过程
当JVM运行过程中,用户需要加载某些类时,会按照下面的步骤(父类委托机制):
1 用户自己的类加载器,把加载请求传给父加载器,父加载器再传给其父加载器,一直到加载器树的顶层。
2 最顶层的类加载器首先针对其特定的位置加载,如果加载不到就转交给子类。
3 如果一直到底层的类加载都没有加载到,那么就会抛出异常ClassNotFoundException。
因此,按照这个过程可以想到,如果同样在CLASSPATH指定的目录中和自己工作目录中存放相同的class,会优先加载CLASSPATH目录中的文件。
Tomcat 类加载(有加载web项目的)
1 使用bootstrap引导类加载器加载
2 使用system系统类加载器加载(tomcat启动所需的类)
3 使用web项目应用类加载器在WEB-INF/classes中加载
4 使用web项目应用类加载器在WEB-INF/lib中加载
5 使用common类加载器在CATALINA_HOME/lib中加载(这个类加载器包含对Tomcat的附加扩展类 位于 $CATALINA_BASE/lib下)
java文件放在Eclipse中的src文件夹下会优先jar包中的class?
双亲委派机制
当一个类加载器需要加载一个目标类时,会先委托父加载器去加载,然后父加载器会在自己的加载路径中搜索目标类,父加载器在自己的加载范围中找不到时,才会交还给子加载器加载目标类。
使用原因:
因为存在同名类时,级别高加载器加载的类就覆盖级别低的,比如你写java.lang.Object永远不会覆盖jdk的。
jvm类加载与tomcat 加载区别
Tomcat的类加载机制是违反了双亲委托原则的,对于一些未加载的非基础类(Object,String等),各个web应用自己的类加载器(WebAppClassLoader,一个web应用有一个自己的WebAppClassLoader,每个jsp文件也都有一个jsploader)会优先加载,加载不到时再交给commonClassLoader走双亲委托。
https://blog.csdn.net/fd2025/article/details/80592099
https://www.cnblogs.com/aspirant/p/8991830.html
内存异常
内存异常分类
方法区溢出 第一种永久区满,说明jar包可能太多,
java heap溢出 堆满的话两种情况程序里面问题,死循环或者有集合加载数据太多
栈溢出 某个线程在跑死循环
内存泄漏(对象已经不使用了,占的内存没有释放)
https://blog.csdn.net/smile_YangYue/article/details/80219001
内存泄漏产生原因
1、单例(生命周期一直存在直到应用停止)中引用了别的实例,别的实例没法消亡一直占着内存
2、集合泄漏;我们通常把一些对象的引用加入到了集合容器(比如ArrayList)中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。
3、资源未关闭造成的内存泄漏
4、非静态内部类和匿名类内部类都会潜在持有它们所属的外部类的引用,但是静态内部类却不会。如果此时内部类一直在使用中,影响着外部类不会被释放
强引用弱引用
强引用:正常对象
软引用:
非必须引用,内存溢出之前进行回收,可以通过以下代码实现
弱引用:
第二次垃圾回收时回收,可以通过如下代码实现
虚引用:
垃圾回收时回收,无法通过引用取到对象值,可以通过如下代码实现
可以通过这个解决大集合对象oom问题,用hashmap,所有对象用一个key标识,值为非强引用,回收后可以再获取对象,