zoukankan      html  css  js  c++  java
  • 实战JAVA虚拟机 JVM故障诊断与性能优化(二)

    认识java虚拟机的基本结构

      java虚拟机基本结构

        

      类加载子系统:负责从文件系统或网络中加载class信息,加载的类信息存放于一块称为方法区的内存空间。除类信息外,方法区中可能还会存放运行时常量池信息,包括字符串常量和数字常量

      java堆:虚拟机启动时建立,它是java程序最主要的内存工作区域,几乎所有的Java对象实例都存放于java堆中,堆空间是所有线程共享的,这是一块与java应用密切相关的内存空间。 

      直接内存:java的NIO库允许java程序使用直接内存,直接内存是java堆外的、直接向系统申请的内存区间。通常,访问直接内存的速度优于java堆,所以读写频繁的场合可以考虑使用java直接内存,由于直接内存在java堆外,因此它的大小不会直接受限于Xmx制定的最大堆的大小,但是系统内存也是有限的,java堆和直接内存的总和受限于系统能给出的最大内存。

      垃圾回收系统:可以对方法区、Java堆、直接内存进行回收,其中java堆是垃圾收集器的重点,全都是隐式的,完成对方法区、Java堆、直接内存全自动化管理。

      Java栈:每一个Java虚拟机线程都有一个私有的Java栈。一个线程的java栈在线程创建时候被创建。Java栈中保存帧信息、局部变量、方法参数,同时和java的方法调用和返回密切相关。

      本地方法栈:与java栈类似,用于本地方法调用。

      PC寄存器(Program Counter):是每个线程私有空间,java虚拟机会为每一个java线程创建pc寄存器。在任意时刻,一个线程总在执行一个方法,这个正在执行的方法为当前方法。如果当前方法不为本地方法,pc寄存器就会指向当前正在被执行的方法。如果当前方法是本地方法,则pc寄存器的值是undefined。

      执行引擎:是java虚拟机最核心的组件之一,它负责执行虚拟机的字节码。现代虚拟机为了提高效率,会使用即时编译技术将方法编译成机器码后再执行。

    学会设置Java虚拟机参数

        java [-options] class [args...]

          -options:java启动参数

          argrs:传递给主函数main()的参数

          class:带有main方法的Java类

        eg: java -Xmx32m simple a     

           -Xmx32m参数传给java虚拟机,使得系统堆内存为32mb,参数a传给main方法。

    辨清java堆内存:

      Java堆是和java应用程序关系最为密切的内存空间,几乎所有的对象都存放在堆中,并且Java堆是完全自动化管理的。

      根据垃圾回收机制的不同,Java堆有可能拥有不同的结构。最为常见的一种是将整个java堆分为新生代和老年代,

       

      s0,s1也被称为form和to区域,两块大小相等。

    eg:

    public class SimpleHeap {

    private int id;

    public SimpleHeap(int id) {
    this.id = id;
    }

    public void show() {
    System.out.println("My Id:" + id);
    }

    public static void main(String[] args) {
    SimpleHeap simpleHeap1 = new SimpleHeap(1);
    SimpleHeap simpleHeap2 = new SimpleHeap(2);
    simpleHeap1.show();
    simpleHeap2.show();
    }
    }
    堆,方法区,java栈分布:

      

    函数如何调用:出入java栈

      java栈线程私有的空间,与线程执行密切相关,函数调用都是通过java栈完成的,在java栈中保存主要内容为栈帧。

      java方法有两种返回函数的方式:

        1.正常的函数返回,使用return指令。

        2.抛出异常,

      不管方式都会导致栈帧被弹出。

      在一个栈帧中,至少包含:局部变量表(保存被调用函数内部的局部变量)、操作数栈(用于计算过程中间的结果)和帧数据区(保存访问常量池的指针,异常处理表)。

      java栈上分配,是java虚拟机提供的一种优化技术,基本思路是线程私有的对象(指不能被其他线程访问的对象),可以分配在栈上,好处是在函数调用结束后自行销毁,而不需要垃圾回收器的介入,提高系统的效率。

    逃逸分析:

      目的是判断对对象的作用域是否有可能逃逸出函数体。

       eg: 

    -server 参数,执行程序,因为在SERVER模式下,才可以启动逃逸分析。
    public class aaa1 {
    private static Date date = null;

    public static void main(String[] args) {
    date = new Date(); //对象date是类成员,该字段有可能被其他线程访问,因此属于逃逸对象。
        }
    }
    public class aaa1 {
          public static void main(String[] args) {
          private static Date date = new Date(); // date 一个非逃逸对象。
        }
    }

      每次函数调用都会占用一定的栈空间,当栈空间不足时,自然不能再调用函数,系统会抛出StackOverflowError栈溢出错误。

      -Xss  来指定线程的最大栈空间,也决定了函数调用的最大深度。

      -XX:+PrintGC  参数,可以看到垃圾回收前后堆的大小变化。

    识别方法区:

      和java堆一样,方法区是一块所有线程共享的内存区域。用于保存系统类的信息,比如类的字段、方法、常量池等。方法区的大小决定保存多少个类。如果程序定义了太多类,则会导致方法区溢出,虚拟机同样会抛出内存溢出的错误。在jdk1.6和jdk1.7中方法区理解为永久区。

      永久区可以使用

      参数 -XX:PermSize 和 -XX:MaxPermSize指定。

      默认-XX:PermSize 为64MB,一个大方法区可以保存更多的类的信息,如果是用到动态代理,怎需要方法区设置大一点。

      eg:

        -XX:+PrintGCDetails -XX:PermSize=5M -XX:MaxPermSize=5m

    补充: 监控jvm的实时动态信息:可以使用jdk自带的Visual VM进行分析,即${JAVA_HOME}/bin/jvisualvm.exe

  • 相关阅读:
    12.1
    我的火车头
    头文件优化时间
    一些姿势
    CodeForces
    CodeForces
    [SDOI 2015] 约数个数和
    BZOJ
    [国家集训队] middle
    鹅的问题
  • 原文地址:https://www.cnblogs.com/kaishi/p/7267186.html
Copyright © 2011-2022 走看看