• JAVA总结--jvm


    VM,Virtual Machine 即虚拟机,指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。

    JVM,Java Virtual Machine 即Java虚拟机,在Java编辑器与OS操作系统之间的虚拟处理器,其模拟计算机的各种功能,将编译后的字节码解释成具体平台上的机器指令执行,从而实现Java的“一次编译,到处运行(Write once, run anywhere)

    一、基本流程

    开发人员编写Java代码(.java文件),然后将之编译成字节码(.class文件),再然后字节码被装入内存,一旦字节码进入虚拟机,它就会被解释器解释执行,或者是被即时代码发生器有选择的转换成机器码执行。

    在Java平台的结构中, 可以看出,Java虚拟机(JVM) 处在核心的位置,是程序与底层操作系统和硬件无关的关键。

    它的下方是移植接口,移植接口由两部分组成:适配器和Java操作系统, 其中依赖于平台的部分称为适配器;JVM 通过移植接口在具体的平台和操作系统上实现;

    在JVM 的上方是Java的基本类库和扩展类库以及它们的API, 利用Java API编写的应用程序(application) 和程序(Java applet) 可以在任何Java平台上运行而无需考虑底层平台, 就是因为有Java虚拟机(JVM)实现了程序与操作系统的分离,从而实现了Java 的平台无关性。 

    JVM在它的生存周期中有一个明确的任务,那就是运行Java程序,因此当Java程序启动的时候,就产生JVM的一个实例;当程序运行结束的时候,该实例也跟着消失了。

    二、Jvm结构

    1、类加载器(ClassLoader):负责从文件系统或者网络中加载Class信息,加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中可能还会存放运行时常量池信息,包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)

    2、方法区(Method Area):用于存储类结构信息的地方,包括常量池、静态变量、构造函数等。虽然JVM规范把方法区描述为堆的一个逻辑部分, 但它却有个别名non-heap(非堆),所以大家不要搞混淆了。方法区还包含一个运行时常量池。

    3、java堆(Heap):在虚拟机启动的时候建立,它是java程序最主要的内存工作区域;几乎所有的java对象实例都存放在java堆中;方法区和堆是被所有java线程共享的。

    4、jvm栈(Stack):线程私有的内存空间;每当创建一个线程时,JVM就会为这个线程创建一个对应的jvm栈;

    5、本地方法栈(Native Method Stack):用于支持native方法的执行,存储了每个native方法调用的状态;jvm栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务;

    6、程序计数器(PC Register):线程私有,用于保存当前线程执行的内存地址。由于JVM程序是多线程执行的(线程轮流切换),所以为了保证线程切换回来后,还能恢复到原先状态,就需要一个独立的计数器,记录之前中断的地方;如果正在执行的是Natvie方法,这个计数器值则为空(Undefined)

    7、执行引擎:负责执行class文件中包含的字节码指令;

    •  java堆

    存放对象实例;完全自动化管理的,通过垃圾回收机制,垃圾对象会被自动清理,而不需要显示的释放;

    常见构成:新生代和老年代,Enden区和两个Survivor区(From和to);Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可;一般按照可扩展来实现的(通过-Xmx和-Xms控制)

    在绝大多数情况下,对象首先分配在eden区,在一次新生代回收之后,如果对象还存活,则进入s0或者s1,

    每经过一次新生代回收,对象如果存活,它的年龄就会加1。当对象的年龄达到一定条件后,就会被认为是老年对象,从而进入老年代。

    java堆、方法区和java栈之间的关系

     1 package com.jvm;
     2 public class SimpleHeap {
     3   private int id;
     4   public SimpleHeap(int id){
     5     this.id = id;
     6   }
     7   public void show(){
     8     System.out.println("My id is "+id);
     9   }
    10 
    11   public static void main(String[] args) {
    12     SimpleHeap s1 = new SimpleHeap(1);
    13     SimpleHeap s2 = new SimpleHeap(2);
    14     s1.show();
    15     s2.show();
    16   }
    17 }

    该代码声明了一个类,并在main函数中创建了两个SimpleHeap实例。此时,各对象和局部变量的存放情况如图:

    SimpleHeap实例本身分配在堆中,描述SimpleHeap类的信息存放在方法区,main函数中的s1 s2局部变量存放在java栈上,并指向堆中两个实例。

    • java栈

    线程私有的内存空间;先进后出的数据结构;主要内容为栈帧(至少包含局部变量表、操作数栈和帧数据区几个部分);每一次函数调用,都会有一个对应的栈帧被压入java栈,每一个函数调用结束,都会有一个栈帧被弹出java栈(进栈出栈)

    当前正在执行的函数所对应的帧就是当前帧(位于栈顶),它保存着当前函数的局部变量、中间计算结果等数据;

     

    每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。 

    两种异常状况:

    如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常(增大-Xss的值);

    如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常。

    1 public static void recursion(){
    2     count++;
    3     recursion();
    4 }

    局部变量表是栈帧的重要组成部分之一;表中的槽位可以重用;

    它用于保存函数的参数以及局部变量,局部变量表中的变量只在当前函数调用中有效,当函数调用结束,随着函数栈帧的弹出销毁,局部变量表也会随之销毁。

    由于局部变量表在栈帧之中,因此,如果函数的参数和局部变量很多,会使得局部变量表膨胀,从而每一次函数调用就会占用更多的栈空间, 死循环下,函数的嵌套调用次数减少;

    局部变量表中的变量也是垃圾回收根节点,只要被局部变量表中直接或者间接引用的对象都是不会被回收的。

    可回收:方法结束变量失去引用后的方法外部,方法内变量被置null失去强引用,变量离开作用域并且再定义新变量复用空间;(销毁变量即可回收)

    小问小答

    类加载 http://blog.csdn.net/boyupeng/article/details/47951037

    概念问题 https://www.toutiao.com/a6421302542316241154/

    调优问题 https://www.toutiao.com/a6511998857537126925/

    GC问题 https://www.toutiao.com/a6493469044564296205/

  • 相关阅读:
    easyui-tree/combotree 子节点前端懒加载(主要解决ie11下加载慢
    解决 Chrome 下表单自动填充问题 (两种方法
    代码编辑器:本地JS文件上传并加载到页面
    PC端使用rem进行屏幕适配
    ECharts 点击非图表区域的点击事件不触发问题
    Angular2+ 使用 Post 请求下载文件
    Express + Element-ui 实现图片/文件上传
    phpMyAdmin -- 没有权限操作用户
    Note of Moment -- 日期处理
    Angular 自定义表单控件 -- CheckboxGroupComponent
  • 原文地址:https://www.cnblogs.com/huasky/p/8117154.html
Copyright © 2020-2023  润新知