zoukankan      html  css  js  c++  java
  • 一纸理解JVM

      JVM,JDK,JRE定义

    • JVM是Java Virtual Machine(Java虚拟机)的缩写。
    • JDK是Java Development Kit JAVA语言开发工具箱(JAVA核心)
    • JRE是Java Runtime Environment 运行环境

      以上三者的关系是这样的

      

    • JDK除了包含JRE以外的,还包含了由把JAVA编译为CLASS的工具,还有监控JVM运行状态的工具jconsole,jcmd,jmat等等
    • JRE包含了运行JAVA的类库等
    • JVM

      JVM特点原理(WRITE ONCE RUN EVERY WHERE)

    • JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。(平台需要安装系统对应的JDK版本)
    • JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令(01010101010)执行。Java语言的一个非常重要的特点就是与平台的无关性。
    • JVM作用和过程,编译器把JAVA源代码编译为类文件,然后通过类加载器把CLASS文件加载进去内存空间,内存空间(方法区,JAVA堆,栈)使用垃圾回收机制来管理内存空间

      为什么需要学习JVM

    • JAVA语言与C等语言不同在于JAVA中对内存管理封装在JVM内部,因此我们要掌握内存管理。才能在程序出现问题时候快速定位,解决问题。
    • 关于内存管理需要学习JAVA运行时数据区,以及JMM内存模型

      运行时数据区

      

      程序计数器:

    • 指向当前线程正在执行的字节码指令的地址 行号 (保护线程记忆)当某一线程被挂起后,线程本身是不知道自己做了什么,挂起恢复后该做什么,因此需要程序来计数器来恢复没做完任务的代码,然后继续完成没做完的任务。当CPU在轮流执行线程的时候,返回原先线程所需要的记录。

      

      虚拟机栈:

    • 存储当前线程运行方法时所需要的数据,指令,返回地址。一个线程对应一个虚拟机栈,一个方法对应一个栈贞,每个栈帧的大小主要由局部变量表的字段决定的栈的大小可以设置Xss来设置,其中一个栈默认大小是1M,栈不能无限生产,一般在3-5K个,栈的大小设置如果太小,面对有方法循环嵌套和递归的方法,栈的大小是不足以存储运行方法所需的数据指令,会发生栈溢出,此时会发生栈扩展,如果栈扩展失败就会造成内存溢出。如果栈的大小设置太大,则会减少可支持的线程数量,面对多线程的环境会造成内存溢出。局部变量表存基本数据类型值,以及引用类型纸箱堆的地址。

      

      本地方法栈:

    • 基本是同虚拟机栈功能结构类似,但是该栈是针对本地方法,也就是说他的栈帧存的方式是本地方法,本地方法是指用NATIVE关键字修饰的方法,实现一般是C++实现的

      方法区:

    • 存储类信息,常量final修饰(1.7以后不包括String常量池),静态变量,JIT(动态代理生产的类信息)

      

      堆:

    • 它是JVM用来存储对象实例,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收。于属性而言,若果是基本数据类型则存放对象和值如果是其他引用类型则存放对象和该对象指向方法区的引用,与方法而言,存放该方法在方法区的地址。

      

      堆中还细分为这种结构(年轻代(1E+2S)年老代和持久代),1.8以后JDK除去了持久代,使用META SPACE来代替,相对于垃圾回收机制而然

      

      年轻代:

    • 所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分三个区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个 Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。可用Xmn设置大小,比例一般是8:1:1,年轻代的大小一般是整个堆大小的30-50%,官方推荐3/8

      年老代:

    • 在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

      持久代:

    • 用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=<N>进行设置。

      JVM内存结构

     

      JVM垃圾回收

    GC (Garbage Collection)的基本原理:将内存中不再被使用的对象进行回收,GC中用于回收的方法称为收集器,由于GC需要消耗一些资源和时间,Java在对对象的生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽可能的缩短GC对应用造成的暂停

    Minor GC

    一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。

    Full GC

    对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个对进行回收,所以比Scavenge GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。有如下原因可能导致Full GC:

    • 年老代(Tenured)被写满
    • 持久代(Perm)被写满
    • System.gc()被显示调用
    • 上一次GC之后Heap的各域分配策略动态变化

     

     

     

  • 相关阅读:
    C++ 将对象写入文件 并读取
    IronPython fail to add reference to WebDriver.dll
    How to Capture and Decrypt Lync Server 2010 TLS Traffic Using Microsoft Tools
    .net code injection
    数学系学生应该知道的十个学术网站
    Difference Between Currency Swap and FX Swap
    Swift开源parser
    谈谈我对证券公司一些部门的理解(前、中、后台)[z]
    JDK8记FullGC时候Metaspace内存不会被垃圾回收
    JVM源码分析之JDK8下的僵尸(无法回收)类加载器[z]
  • 原文地址:https://www.cnblogs.com/zhuoqingsen/p/JVM.html
Copyright © 2011-2022 走看看