idea安装好热加载插件 JRebel,启动后报错java.lang.OutOfMemoryError: PermGen space解决方法
报错缘由是由于内存溢出了,也就是内存不足,方法就是增长内存,添加以下配置:java
参数解释:
-Xms,表示程序启动时,JVM 堆的初始化最小尺寸参数;
-Xmx,表示程序启动时,JVM 堆的初始化最大尺寸参数;
-XX:PermSize,表示程序启动时,JVM 方法区的初始化最小尺寸参数;
-XX:MaxPermSize,表示程序启动时,JVM 方法区的初始化最大尺寸参数。安全
激活JRebel
生成 GUID 的网址:https://www.guidgen.com/网络
用这个网址 + 生成的 GUID 激活数据结构
https://jrebel.qekang.com/
例如:jvm
https://jrebel.qekang.com/cb2546bb-9d43-4115-bf4b-10539349efed
File -> Settings -> JRebel -> [Work offline]按钮
既然用了这个热加载,就了解一下这个热加载原理ide
java的类加载过程
一个java类文件到虚拟机里的对象,要通过以下过程:
首先咱们编写好了的java源代码经过java编译器,将java源代码文件编译成class字节码,类加载器读取class字节码,再将类转化为实例,对实例newInstance就能够生成对象。
类加载器ClassLoader功能,也就是将class字节码转换为类的实例。在java应用中,全部的实例都是由类加载器,加载而来。通常在系统中,类的加载都是由系统自带的类加载器完成,并且对于同一个全限定名的java类(如com.csiar.soc.HelloWorld),只能被加载一次,并且没法被卸载。工具
加载class字节码的工做是由类加载器实例去实现的,类加载器支持经过文件目录,jar,zip,网络等多种途径,加载class字节码文件。
JVM启动后就默认有三个类加载器实例,负责去加载不一样位置的class。
1.核心类库加载器 BootStrap ClassLoader,负责加载jdk安装目录下lib文件夹里面的jar包,咱们的String.class,System.class这些类都放在这个目录下面,启动jvm就会去加载,必不可少。
2.拓展类库加载器 Extension ClassLoader,负责加载jdk安装目录下lib/ext文件夹里面的jar包,这里面是一些jdk的拓展jar包,好比zipfs.jar这样的包或工具类。拓展的意思就是在某些状况下,这些jar包不加载也不影响jvm工做。
3.应用程序代码加载器 Application ClassLoader,负责加载咱们本身写的程序代码,经过java命令 -cp 或者 -classpath告诉jvm咱们的代码class存放位置。若是咱们的程序是jar包运行,你能够在jar包 META-INF目录MANIFEST.MF文件里面看到一个Class-Path: .配置,这就是指定代码位置的。布局
java类加载的阶段
加载阶段
找到类的静态存储结构,并加载到虚拟机里面,而后转换成方法区的运行时数据结构,生成class对象,加载阶段,用户能够自定义类加载器参与进来。
验证阶段
主要确保字节码安全的,确保不会对虚拟机安全形成危害,能够经过JVM启动参数来禁用一些验证,但不推荐修改设置,参数禁用可能会对虚拟机安全形成一些危害。
准备阶段
肯定内存布局,初始化内存变量,注意点:赋初始值,不会执行程序本身定义的赋值操做,好比定义了一个私有变量:private static int count = 12,在准备阶段并非把count初始为了12,这里是会赋初始值,int初始值为0,因此会把这私有静态变量赋值为0,而不是12。
解析阶段
这个阶段主要是将符号引用变为直接引用。
初始化阶段
调用程序自定义的代码。好比private static int count = 12, count在本阶段将会被初始化为12,而不是以前准备阶段的0,初始化阶段会生成clean int 方法,这个方法由编译器自动收集类中的全部类变量的赋值、动做和静态语句块中的语句合并,同一个类加载器中,只会将一个类型初始化一次。post
Java虚拟机没有强制约束何时开始初始化阶段,但规定了5种状况必须当即初始化,固然这以前的几种操做都是已经运行了的。5种状况以下:ui
1.遇到new、 get static 、post static、 invoke static这四条字节码指令的时候,若是类没有初始化,须要触发初始化,注意的是final修饰的类,会在编译期的时候,将结果放在常量池,即便调用也不会触发初始化,由于final修饰的是常量,会把常量放在常量池,调用常量不会触发初始化这个阶段。
2.使用java.long.reflect包里方法,即对类进行反射调用的时候,若是类没初始化的话,须要初始化。
3.当初始化一个子类的时候,若是父类尚未初始化,须要先初始化父类,再初始化子类。
4.虚拟机启动的时候,用户制定一个要执行的主类,虚拟机会先初始化这个主类,例子:咱们写的java程序,在某一个类里面写了一个main方法,经过运行这个main方法启动这个程序,虚拟机会先初始化这个main方法所在的类。
5.使用jdk1.7动态语言支持的时候,若是java.lang.invoke.methondhandler类实例解析的最后结果是ref_getstatic、ref_putstatic、ref_invokestatic方法句柄的时候,若是句柄对应的类没有初始化,那就须要先初始化句柄对应的类。
1.由AppClass Loader(系统类加载器)开始加载指定的类;
2.类加载器将加载任务交给其父类,若是其父类找不到,再交给本身去加载(即双亲委派);
3.Bootstrap Loader (启动类加载器)是最顶级的类加载器。
热加载的实现原理主要依赖java的类加载机制,在实现方式能够归纳为在容器启动的时候起一个后台线程,定时的检测类文件的时间戳变化,若是类的时间戳变化了,则将类从新载入。
对比反射机制,反射是在运行时获取类信息,经过动态的调用来改变程序行为; 热加载则是在运行时经过从新加载改变类信息,直接改变程序行为。