zoukankan      html  css  js  c++  java
  • java虚拟机

    java语言由四部分组成:java虚拟机,java程序语言,Java API(提供各开发领域的接口),第三方java框架(Spring,Struts 2)
    为什么要深入学习java虚拟机呢?
    一个简单的程序可能在10个人同时使用时完全正常,但是在10000个人同时使用时就会非常缓慢,死锁,甚至崩溃。然而企业中的应用,面向的是整个社会,任意时刻都可能有多人访问应用程序,这时就需要对java虚拟机的特性及调优具有深入的认识,以保障系统的性能、并发和伸缩能力。(架构师,高级程序员,系统调优师)

    java程序语言(包括一些工具),java虚拟机,java API类库 统称为JDK(Java Development Kit)

    javaSE API和java虚拟机这两部分内容统称为JRE(Java Runtime Environment)

    The Java Runtime Environment (JRE) provides the libraries, the Java Virtual Machine, and other components to run applets and applications written in the Java programming language.

    The JDK is a superset of the JRE, and contains everything that is in the JRE, plus tools such as the compilers and debuggers necessary for developing applets and applications.

    java SE(Standard Edition):API以java.*为包名

    java EE(Enterprise Edition):API以javax.*为包名
    HotSpot VM是Sun JDK和OpenJDK所带的虚拟机,也是目前使用范围最广的虚拟机。
    java虚拟机 自动内存管理机制:java程序员把内存控制的权力交给了java虚拟机,不需要为每一个new操作去写配对的delete/free代码,不容易出现内存泄露和内存溢出的问题。
    内存溢出(OutOfMemoryError):垃圾无法回收,一直占用内存,导致建立新的对象时内存不够用。
    内存泄露(memory leak):一些对象始终占用内存,不被GC回收掉。
    -----------------------------------------------------------------------------------------
    java虚拟机的内存模型:
    1.程序计数器:线程在执行.class字节码文件的时候的行号指示器
    2.java虚拟机栈(栈内存):每个方法在执行时都会创建一个帧栈(存放局部变量表,操作数栈,方法出口等),一个方法从调用到执行完成的过程,就对应着一个帧栈在虚拟机栈中入栈到出栈的过程。
    局部变量表存放了基本类型,对象引用。
    3.java堆:存放所有的对象实例,以及数组。
    java堆是垃圾回收器管理的主要区域,因此也叫GC堆。
    4.本地方法栈:与java虚拟机栈的功能非常相似,但本地方法栈是为虚拟机使用到的native 方法服务的。
    什么是native 方法?
    ----一个native method就是一个java调用非java代码的接口,该方法的实现由非java语言实现,比如C语言。
    5.方法区:被各个线程共享,用于存储虚拟机加载的类信息,常量,static变量(全局变量),字符串常量池(String s="libi";这个“libi”就是保存在方法区中的)
    6.运行时常量池:属于方法区的一部分
    7.直接内存:不属于虚拟机运行时数据区的一部分,也不是java虚拟机规范定义的内存区域。
    NIO使用native函数库直接分配堆外内存,在一些场景中显著提高性能。
    --------------------------------------------------------------------------------------------------------
    Eclipse Memory Analyzer插件:内存映像分析工具,如果java堆出现内存泄露或者内存溢出,则可以用它来分析堆转储快照(Heap Dump)。
    通过vm参数:-XX:+HeapDumpOnOutOfMemoryError可以获得堆转储快照
    -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
    这句话设置java堆最小值20MB,最大堆20MB,不可扩展
    vm参数:-Xss128k        设置java虚拟机栈容量大小为128K
    如果线程请求的栈深度大于虚拟机所允许的最大深度,则会抛出StackOverflowError
    (函数调用层级过多,比如死递归,当前线程的栈就满了,就会抛出StackOverflowError)
    vm参数:-XX:PermSize=10M -XX:MaxPermSize=10M   设置方法区的大小,从而间接限制运行时常量池的大小。
    方法区用于存储Class类相关的信息,如果运行时产生大量的类去填满方法区,则会导致方法区溢出。
    ---------------------------------------------------------------------------------------
    垃圾回收器(GC):内存回收主要是针对java堆和方法区,因为其他内存区域随着线程的结束或者方法结束,内存自然就回收了。但是一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,只有在程序运行期间才知道创建哪些对象。
    GC如何判断某个对象是否死亡然后回收掉?
    可达性分析算法:以GC Roots对象作为起始点,从这个对象往下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链时,则说明该对象不可用了。
    java虚拟机栈中引用的对象就可以作为GC Roots
    强引用:Object obj=new Object();     obj即为强引用,只要强引用存在,垃圾回收器永远不会回收掉被引用的对象。
    软引用:在下下次GC时进行回收
    弱引用:被弱引用关联的对象只能生存到下一次垃圾回收之前
    虚引用:当对象被回收时得到一个系统通知
    为什么要回收方法区的类型?
    如果某个字符串“abc”不再被引用,则需要被回收
    卸载无用的类(.class)
    无用的类必须同时满足以下3个条件方可被回收:
    1.该类的所有实例都已经被回收
    2.加载该类的ClassLoader已经被回收
    3.该类的java.lang.Class对象没有在任何地方被引用
    垃圾回收算法:当前商业虚拟机的垃圾回收器采用的是“分代收集”算法。把java堆分为新生代和老年代,新生代(每次GC都发现有大量对象死去,则使用复制算法),老年代(对象存活率高,使用“标记-整理”算法)
    推荐博客:http://my.oschina.net/winHerson/blog/114391
    复制算法:将新生代分为3个区域Eden:Survivor:Survivor=8:1:1
    回收时,将Eden和Survivor中还存活的对象一次性复制到另外一个Survivor空间中,然后清理Eden和刚才用过的Survivor空间。
    新生代中的可用内存空间为:80%+10%=90%
    当今垃圾收集器最屌的是G1收集器:
    G1(Garbage-First):优先回收价值最大的Region.
    Minor GC:发生在新生代,回收速度快而且Minor GC非常频繁
    Full GC:发生在老年代,会导致“Stop the World”,即停顿所有的执行线程,专门完成垃圾回收。如果内存空间碎片过多,无法找到足够大的连续空间来分配当前对象,就会提前触发Full GC
    大对象(需要大量连续内存空间的java对象,例如很大的数组)会直接进入老年代。
    虚拟机参数:-XX:PretenureSizeThreshold=3145728
    凡是大于这个参数的对象直接进入老年代分配
    长期存活的对象将进入老年代:虚拟机给每个对象定义了一个对象年龄(Age)计数器,如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能够被Survivor容纳的话,将被移动到Survivor空间,并且对象年龄为1.对象在Survivor中每熬过一次Minor GC,年龄就增加1岁,当超过15岁(默认)时,就会进入老年代。
    虚拟机参数 -XX:MaxTenuringThreshold=15
    ------------------------------------------------------------------------------
                       (通过javac编译器)                                   jvm
    .java源程序—————————>.class(字节码文件)--------->执行
    字节码文件是二进制流,可以通过javap查看字节码文件
    Java语言是跨平台的,其跨平台的基石是字节码
    .class字节码文件的数据结构:整个class文件分Magic,Version,Constant_pool,Access_flag,This_class,Super_class,Interfaces,Fields,Methods,Attributes几个部分
    博客:http://blog.csdn.net/a19881029/article/details/16117251



    java虚拟机的字节码指令集:用于解释执行字节码文件
    指令由操作码(一个字节长度,代表某种特种操作含义的opcode)和操作数(零至多个代笔此操作所需参数的operands)组成
    推荐博客:http://www.cnblogs.com/ggzwtj/archive/2012/03/26/2418634.html
    -------------------------------------------------------------------------------
    虚拟机如何加载.class字节码文件的呢?
    C或者C++在编译时就需要进行连接工作,而java里面,类的加载、连接和初始化都是在程序运行期间完成的(运行期动态加载)。
    在程序运行期间,需要什么字节码文件,就加载什么字节码文件在虚拟机内存中执行。
    虚拟机的类加载机制:
    加载->验证->准备->解析->初始化->使用->卸载
              ————————(连接)
    在什么时候虚拟机会加载类并完成初始化呢?
    1.使用new关键字实例化对象,读取或设置一个类的静态字段,或者调用一个类的静态方法
    (final static修饰的内容会放入运行时常量池中,不算在其中)
    /**用static修饰的代码块表示静态代码块,当Java虚拟机(JVM)加载类时,就会执行该代码块**/
    2.使用java.lang.reflect包的方法对类进行反射调用的时候
    3.当初始化一个类时,发现其父类还没有进行过初始化,需要先触发其父类的初始化
    4.当虚拟机启动时,会先初始化包含main()函数的主类



    虚拟机如何加载一个类呢?
    1.通过一个类的全限定名来获取此类的字节码文件
    2.将字节码所代表的静态存储结构转化为方法区的运行时数据结构
    3.在堆中生成代表这个类的java.lang.Class对象,作为各种数据的访问入口。
    验证:验证字节码文件的合法性
    准备:在方法区为static变量或者类变量赋予初始值
    一般在需要实现以下两个功能时使用静态变量:
      在对象之间共享值时
      方便访问变量时
    为了方便方法的调用,Java API中的Math类中所有的方法都是静态的,而一般类内部的static方法也是方便其它类对该方法的调用。
    被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享。
    static的方法只能在其中使用不属于本方法的static变量。非static方法能使用不属于本方法的static变量。只要这个类被加载,Java虚拟机就能根据类名在方法区内找到他们。因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。
    初始化:开始真正执行字节码。初始化类变量和其他资源
    是执行类构造器<clinit>方法的过程,运行static{}静态语句。
    -------------------------------------------------------------------------------
    类加载器:类加载器是放到java虚拟机外部去实现的,它可以将一个类加载到java虚拟机中    类加载器都继承自抽象类java.lang.ClassLoader
    类加载器分为:启动类加载器(负责将<JAVA_HOME>lib目录中的类库加载到虚拟机内存中),扩展类加载器,应用程序类加载器(程序默认的类加载器)
    ClassPath(ja环境变量,应用程序类加载器就是加载classpath中的类)
    ClassPath——%JAVA_HOME%libdt.jar;%JAVA_HOME%lib ools.jar
    Path:用于找到javac,java,javap和一些虚拟机监控的命令。
    Path——%JAVA_HOME%in,%JAVA_HOME%jrein
    双亲委派模型:当类加载器得到命令需要加载某个类时,它不会自己去加载,而是把任务委派给父类,直到父类无法加载时,子加载器才会尝试自己去加载。
    -------------------------------------------------------------------------------------
    虚拟机字节码执行引擎:当把字节码文件加载到java虚拟机后,就需要虚拟机字节码执行引擎去执行这些字节码了,其中又分为解释执行(通过解释器执行)和编译执行(通过即时编译器产生本地代码执行)。
    -------------------------------------------------------------------------------------
    为什么要学习java虚拟机呢?
    主要是为了解决高效并发的问题,也就是高并发。











            

  • 相关阅读:
    PlantsVsZombies_v2.0_1
    attackZombie如何实现符合需求的攻击函数_3
    attackZombie如何实现符合需求的攻击函数_2
    list_head.h
    attackZombie如何实现符合需求的攻击函数
    PlantsVsZombies_3
    串口服务器在激光切割机远程监控系统中的使用
    串口转以太网服务器在物联网中的行业应用
    物联网能源系统应用解决方案和作用什么?
    4G工业路由器在智能安防和监控中的应用
  • 原文地址:https://www.cnblogs.com/james111/p/6607394.html
Copyright © 2011-2022 走看看