浅谈JVM

目录

1、类加载机制

2、双亲委派模型

3、破坏双亲委派模型

4、native关键字

5、Java内存

6、GC回收

7、GC的回收算法


1、类加载机制

1.1第一阶段:加载

就是把一些.java的文件通过javac编译后生成的.Class文件以二进制流保存到JVM内存中去,JVM中会在方法区中为该类创建一个对应的Class对象,这个Class对象就是以后访问该类的一个入口

1.2第二阶段:验证

就是的到的这个Class字节码文件是否符合Java的要求。一样的验证有魔术验证、版本验证、代码是否规范验证

1.3第三阶段:准备

主要是为类的变量分配内存和初始化类型

分配内存的对象:这里的对象指的是类对象,即就是static修饰的变量,给该对象进行分配内存

初始化类型:就是把分配内存的对象进行初始化赋值,这里的赋值并不是用户给与该变量的值,而是Java默认赋予的值。除非该变量是被final static修饰的,那么在进行初始化的时候就会赋值为用户给予的值。因为final修饰的变量是最后的、不能改变的。而非final修饰的关键字有可能在初始化或者运行阶段其值可能会改变。

1.4第四阶段:解析

主要是为了把常量池的中的符号引用转换成在内存中的直接引用

1.5第五阶段:初始化

把用户写的Java代码执行,遇到需要初始化的代码就开始初始化

初始化的条件

new、getstatic、putstatic、invokestatic 这四条字节码指令时

使用 java.lang.reflect 包的方法对类进行反射调用的时候

当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化

1.6第六阶段:使用

在main方法中执行用户的程序代码

1.7第七阶段:卸载

程序运行结束之后就会把创建的Class对象销毁,JVM退出

2、双亲委派模型

双亲委派机制是指一个类加载器在收到类加载请求后不会尝试自己加载这个类,而是把该类加载请求向上委派给其父类加载器去完成,其父类加载器在接收到该类加载请求后又会将其委派给自己的父类,以此类推,这样所有的类加载请求都被向上委派到启动类加载器中。若父类加载器在接收到类加载请求后发现自己也无法加载该类(通常原因是该类的Class文件在父类的类加载路径中不存在),则父类会将该信息反馈给子类并向下委派子类加载器加载该类,直到该类被成功加载,若找不到该类,则JVM会抛出ClassNotFoud异常

类加载流程图

preview

  1. 应用程序类加载器将类加载请求委托给扩展类加载器。

  2. 扩展类加载器将类加载请求委托给启动类加载器。

  3. 启动类加载器在加载路径下查找并加载Class文件,如果未找到目标Class文件,则交由扩展类加载器加载。

  4. 扩展类加载器在加载路径下查找并加载Class文件,如果未找到目标Class文件,则交由应用程序类加载器加载。

  5. 应用程序类加载器在加载路径下查找并加载Class文件,如果未找到目标Class文件,就抛出异常Class not find

3、破坏双亲委派模型

重写ClassLoader中的LoadClass()方法就可以打破双亲委派模型

主要是修改其中的路径

   @Override
 public Class<?> loadClass(String name)  throws ClassNotFoundException {
     String Path = "D:/Idea/class/" + name.replace(".","/") + ".class";
 }

不想破坏双亲委派模型就重写ClassLoader里面的findClass方法

4、native关键字

native表示本地的,native修饰的一些方法叫做本地方法,本地方法并不是Java是实现的,而是通过C/C++实现的

在jvm内存中,有一个本地方法栈,这个栈里面保存的就是本地方法,在需要去使用这些本地方法的时候,就会通过Java native interface去获取本地方法库里面的方法

JNI调用C的流程图

5、Java内存

方法去和堆是线程共享资源区域,其他三部分是线程私有的 

5、1程序计数器

程序计数器是Java内存中分配的一小块内存,用来存放执行某些线程指令,属于线程的私有内存。因为Java是轮流执行线程也就是说同一时刻,一个处理器只能执行一个线程的指令。这是唯一一个在任何情况下都不会抛出OutofMemoryError错误

5、2虚拟机栈

虚拟机栈也是线程私有的内存,在执行一个方法的时候首先会在栈中创建一个栈帧用于存放的执行该方法的一些局部变量、方法出口等。

一个方法从执行到结束的一个过程就对应一个栈帧从入栈到出栈的过程

5、3本地方法栈

顾名思义就是用来存放本地native方法的内存

5、4堆

堆在启动虚拟机的时候就会创建堆内存,该内存是所有线程共享的一块内存空间。主要是用来存放对象的实例。该内存是主要的回收垃圾的地方。堆中分为三部分:

新生区:创建对象实例都是存储在这一块,也就是通过new出来的对象

养老去:通过重量级的垃圾回收后新生区内存满后,进行存储数据,其数据不可能在被改变

永久区:存储的是JDK自带的一些jar包,interface元接口,以及一些类信息。在这一块内存中不存在垃圾回收,关闭jvm后内存里面的东西就会被释放。

造成在永久区就出现了OOM的原因:加载一个类的时候加载了太多的jar包,部署了Tomcat了很多的应用。

处理OOM问题:使用jprofiler工具进行快速查找出现问题的代码。

好处:会生成一个Dump文件,获取大的对象,获取堆中的数据

-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError

-Xms128m JVM初始分配的堆内存 -Xmx512m JVM最大允许分配的堆内存,按需分配 -XX:PermSize=64M JVM初始分配的非堆内存 -XX:MaxPermSize=128M JVM最大允许分配的非堆内存,按需分配

5、5方法区

该区域也是线程共享的,主要是用来存放静态变量、final修饰的变量、加载过的类信息、即时编译器编译过后的代码等内容。在该内存中存在垃圾回收很少,即使有都是对常量池的回收和变量类型的卸载

5、6运行时常量池

在Class文件中不仅存放类的版本、方法、接口、变量还有常量池,是用来存放在编译期间生成的字面量和符号引用,在加载类的时候,这部分内容会存在于方法区中的运行时常量池中。在运行期间也可以新的常量加入运行时常量池中

6、GC回收

垃圾回收主要是在堆中

垃圾回收流程:所有对象的实例都是保存在堆中的伊甸园区中,在伊甸园区被存满后就会进行轻量级的垃圾回收,在此次垃圾回收中幸存下来的对象实例就会被保存在幸存from区,当幸存from区存满后就会往幸存to区进行存,这两个幸存区之间是一种动态的转换的。在新生区的内存被存满后就会进行重量级的垃圾回收(FullGC),经过重量级垃圾回收之后还能生存下来的数据就会被保存在养老区。当养老区的内存被存满时就会抛出OOM问题

 //jvm初始化的最大内存
 long val=   Runtime.getRuntime().totalMemory();
 //虚拟机提供的最大内存
 long max=Runtime.getRuntime().maxMemory();
 System.out.println(val+" "+(val/1024/1024));
 System.out.println(max+" "+(max/1024/1024));
 //内存调优:-Xms1024m -Xms1024 -XX:+PrintGCDetails


7、GC的回收算法

7、1引用计数法

该原理就是给每个对象做一个计数,通过在执行过程中来对对象进行计数的获取,从而判断该对象是否被当做垃圾回收,若某个对象没有被进行计数为0,则说明该对象没有被使用过,被当作垃圾回收掉。给对象做标记也会占用到一些内存

图中的对象A在轻度垃圾回收过程中就会被回收

7、2复制清除算法

复制算法主要是用于新生区,在新生区中的幸存to 和幸存from之间来回进行数据的赋复制,这两个区之间的to from是来回切换的,并非固定的,在保存数据的过过程中会一直保持一个区是空的,而空的这个区就是幸存to区。

回收流程图

好处:没有内存碎片

坏处:浪费了内存空间,因为幸存to区是空的

7、3标记清除法

就是给一些对象做一些标记,在进行垃圾回收的时候通过已有的标记来判断对象是否需要被清除,没有被标记的对象就会被清除。

好处:不会浪费内存

坏处:两次扫描浪费时间,清除垃圾之后会有内存碎片

7、4标记压缩法

建立在标记法的基础之上,再把保留下来的对象往前面移动,让那些内存碎片成为连续的内存

好处:不会浪费内存,清除垃圾之后不会有内存碎片

坏处:三次扫描浪费时间

算法比较

内存效率:复制法 》标记清除法 》标记压缩法

内存利用率:标记清除法==标记压缩发 》复制法

内存整齐度:复制法==标记压缩法 》标记清除法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值