深入理解JVM

2019/10/23 18:44
阅读数 15

深入理解JVM


1. JVM运行机制及原理

  JVM是JRE的一部分,是一个虚构出来的计算机,有着一套完整的硬件架构体系。 java程序之所以拥有着跨平台性,这也就是jvm的功劳。首先java源程序.java文件通过编译器编译成.class文件,然后java解释器又将这编译后的字节码,解释成特定的机器码运行。

JVM运行机制及原理

2. jvm内存机制

运行时数据区

  Jvm内存区域分为三大块:类装载器、运行时数据区、执行引擎。

2.1 类装载器

  类装载器负责加载程序中的类型(类和接口),并赋予唯一的名字。同时类装载器分为启动类装载器和用户自定义类装载器。

2.2 运行时数据区

运行时数据区2

<font color="red">- 运行时数据区由以下几个部分组成:</font>

  1. 堆内存:

  存放程序运行时new出来的对象,同时堆内存在JVM中属于线程共享的,因此对象内存的分配均需要进行加锁,这也导致了new对象的开销是比较大的。开发中也常使用单例模式或者配置一个bean容器,来创建一个常用的实例对象。

  1. 栈内存:

  每个方法被执行的时候,都会同时创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、对象引用地址、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

  1. 程序计数器:

  一块很小的内存空间,作用是当前线程所执行的字节码的行号指示器。

  1. 本地方法栈:

  与虚拟机栈作用很相似,区别是虚拟机栈为虚拟机执行java方法服务,而本地方法栈则是为虚拟机用到的Native方法服务。(Java程序调用了非Java代码)

  1. 方法区:

  用于存放已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。

  方法区同时包含运行时常量池,用于存放编译期生成的各种字面量和符号引用。这里也有一个特性,就是对象比较。(注意:jdk1.8常量池位于方法区中,但常量池引用的字符串实例却在堆中。)

运行时常量池

2.3 执行引擎

  用来执行字节码或本地方法。主要采用方式:解释,即时编译,自适应优化。

3. JVM垃圾回收

  1. GC什么时候启动

  GC是一个动态优先级的守护进程。当内存资源低到一定限度时便会自动运行,从而实现对内存的回收。这就是垃圾回收的时间不确定的原因。

  告诉程序尽快启动一次GC代码:system.gc()

  1. 被GC回收的对象

  程序运行期间,所有对象实例存储在运行时数据区域的heap中,当一个对象不再被引用(使用),它就需要被收回。在GC过程中,这些不再被使用的对象从heap中收回,这样就会有空间被循环利用。

  1. GC是如何回收对象的

  在对对象的生命周期特征(eden or survivor)进行分析之后,采用了分代的方式进行对象的收集,以缩短GC对应用造成的暂停。

  这种"自适应式"垃圾回收机制,会自动的进行分代、停止-复制、标记-清扫等方式进行垃圾回收。它会根据不同的环境选择不同的处理方式。

  1. JVM次世代划分

    <u>新生代与旧生代策略作用于堆内存中,而持久代策略作用于方法区中</u>

    • 新生代 Young Generation

      1. Eden Space 任何新进入运行时数据区域的实例都会存放在此

      2. S0 Suvivor Space 存在时间较长,经过垃圾回收没有被清除的实例,就从Eden 搬到了S0

      3. S1 Survivor Space 同理,存在时间更长的实例,就从S0 搬到了S1

    • 旧生代 Old Generation/tenured   同理,存在时间更长的实例,对象多次回收没被清除,就从S1 搬到了tenured
    • 持久代 Perm   存放运行时数据区的方法区
  2. 开发中可回收垃圾产生演示

JVM 分别对新生代和旧生代采用不同的垃圾回收机制

何为垃圾?

Java中那些不可达的对象就会变成垃圾。那么什么叫做不可达?其实就是没有办法再引用到该对象了。主要有以下情况使对象变为垃圾:

  • 对非线程的对象来说,所有的活动线程都不能访问该对象,那么该对象就会变为垃圾。
  • 对线程对象来说,满足上面的条件,且线程未启动或者已停止。
例如: 
(1)改变对象的引用,如置为null或者指向其他对象。 
   Object x=new Object();//object1 
   Object y=new Object();//object2 
   x=y;//object1 变为垃圾 
   x=y=null;//object2 变为垃圾 
(2)超出作用域 
   if(i==0){ 
      Object x=new Object();//object1 
   }//括号结束后object1将无法被引用,变为垃圾 
(3)类嵌套导致未完全释放 
   class A{ 
      A a; 
   } 
   A x= new A();//分配一个空间 
   x.a= new A();//又分配了一个空间 
   x=null;//将会产生两个垃圾 
(4)线程中的垃圾 
   class A implements Runnable{   
     void run(){ 
       //.... 
     } 
   } 
   //main 
   A x=new A();//object1 
   x.start(); 
   x=null;//等线程执行完后object1才被认定为垃圾 
   这样看,确实在代码执行过程中会产生很多垃圾,不过不用担心,java可以有效地处理他们。
展开阅读全文
打赏
1
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
1
分享
返回顶部
顶部