标签:需要 工作 加锁 私有 rtu jdb 栈内存 结构 情况下
JDK:JDK是Java开发工具包,是Sun Microsystems针对Java开发员的产品。JDK中包含JRE(在JDK的安装目录下有一个名为jre的目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib和起来就称为jre)和一堆Java工具(javac/java/jdb等)和Java基础的类库(即Java API 包括rt.jar)。
Java Runtime Environment(JRE):是运行基于Java语言编写的程序所不可缺少的运行环境。也是通过它,Java的开发者才得以将自己开发的程序发布到用户手中,让用户使用。JRE中包含了Java virtual machine(JVM),runtime class libraries和Java application launcher,这些是运行Java程序的必要组件。
JVM(java virtual machine):就是我们常说的java虚拟机,它是整个java实现跨平台的最核心的部分,所有的java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行。
JVM就是运行在操作系统之上的一个软件
JVM的组成:
======================类加载器=======================
类加载器(ClassLoader):负责加载class文件(classs文件在文件开头有特定的文件标识),将class文件字节码内容加载到内存中,并将这些内容转换成方法区中的运行时数据结构;ClassLoader只负责加载class文件的加载,至于它是否可以运行,则由Execution Engine决定。
1、BootStrapLoader(引导类加载器):类加载器也是java类,他们也需要类加载器加载进入内存,显然必须要有第一个不是java类的类加载器,来完成这个工作,这个正是BootStrap。负责加载存放在D:\Program Files (x86)\Java\jdk1.7.0_79\jre\lib下,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库(如rt.jar,所有的java.*开头的类均被Bootstrap ClassLoader加载);启动类加载器是无法被Java程序直接引用的;rt.jar 里面的类的加载器都是BootStrapLoader。
2、Extension ClassLoader(扩展类加载器):该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载D:\Program Files (x86)\Java\jdk1.7.0_79\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库(如javax.*开头的类),开发者可以直接使用扩展类加载器。ext 目录下所有的类的加载器都是Extension ClassLoader
3、Application ClassLoader(应用程序类加载器):该类加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
====================JVM类加载机制==============
全盘负责:当前线程的类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用CLassLoader.loadClass()指定类加载器来载入
父类委托:先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。所以我们在开发中尽量不要使用与JDK相同的类(例如自定义一个java.lang.System类),因为父类加载器中已经有一份java.lang.System类了,它会直接将该类给程序使用,而你自定义的类压根就不会被加载。
双亲委派模型:
双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,
只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。
双亲委派机制:
双亲委派模型意义:
==================类的加载过程======================
类的加载过程:JVM将javac编译好的class字节码文件加载到内存中,并对该数据进行验证、解析和初始化、形成JVM可以直接使用的JAVA类,最终回收(卸载)的过程。
字节码(.class)文件来源:
1、加载:加载阶段其实就是JVM通过一个类的全限定名来获取其定义的二进制字节流,并将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构且在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。在该阶段我们开发人员可以干预,例如:我们可以指定类加载器来加载该字节数组或者自定义类加载器来加载。
2、链接:将java类的二进制代码合并到JVM的运行状态中的过程
3、初始化:初始化为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。
4、使用:程序使用JVM加载的类
5、卸载
1、方法区(Method Area):方法区是各个线程共享的内存区域;方法区用于存储已被虚拟机加载的类的模板信息、常量、静态变量等;虽然Java虚拟机规范把方法区描述为堆的一部分,但是他还有个别名叫做Non-heap(非堆),目的应该是与Java堆区分开来;根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError 异常;相对而言,垃圾收集在这个区域是比较少出现的,但并非数据进入了方法区就如永久代的名字一样永久存在了。这区域的内存回收目标重要是针对常量池的回收和类型的卸载。
方法区只是一个规范:
2、PC寄存器(程序计数器):每个线程都有一个程序计数器,是线程私有的;就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,既将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记;它是当前线程所执行的字节码的行号指示器,字节码解释器通过改变这个计数器的值来选取下一条需要执行的字节码指令。如果执行的是一个Native方法,那这个计数器是空的;用以完成分支、循环、跳转、异常处理、线程恢复等基础功能。不会发生内存溢出OOM错误
本地方法栈(Native Stack):与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的java方法服务,而本地方法栈则是为Native方法服务。(栈的空间大小远远小于堆)
3、虚拟机栈(Vm Stack)
栈也叫栈内存,主管 Java 程序的运行,是在线程创建时创建,它的生命期是跟随线程的生命期,线程结束栈内存也就仔放,对于栈来说不存在垃圾回收问题,只要线程结束该栈就释放,生命周期和线程一致,是线程私有的。8种基木类型的变量+对象的引用变量+实例方法都是在函数的栈内存中分配。
栈的运行原理:栈中的数据都是以栈帧(Stack Frame)的格式存在,栈帧是一个内存区块,是一个数据集,是一个有关方法( Method )和运行期数据的数据集,当一个方法A被调用时就产生了一个栈帧 Fl ,并被压入到栈中, A方法又调用了B方法,于是产生栈帧 F2 也被压入栈,B方法又调用了C方法,于是产生栈帧 F3 也被压入栈,执行完毕后,先弹出 F3 栈帧,再弹出 F2 栈帧,再弹出 Fl 栈帧 以此类推, 遵循“先进后出” / “后进先出”原则。每个方法执行的同时都会创建一个栈帧,用于存储局部变量表、操作数、动态链接、方法出口等信息,每一个方法从调用直至执行完毕的过,就对应着一个栈帧在虚拟机中入栈到出栈的过程。栈的大小和具体JVM的实现有关,通常在 256K~1024K 之间, 1M 左右。
JVM栈的特点:
4、本地方法栈(Native Method Stacks):与虚拟机栈所发挥的作用是非常相似的,他们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的本地Native方法服务‘;在虚拟机规范中对本地方法栈中的使用方法、语言、数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(例如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。本地方法栈也会抛出StackOverFlowError和OutOfmMemoryError异常。
5、Java堆(Java Heap):是Java虚拟机管理内存中的最大一块;Java堆是所有线程共享的一块内存管理区域。此内存区域唯一目的就是存放对象的实例,几乎所有对象实例都在堆中分配内存。这一点在Java虚拟机规范中的描述是:所有对象实例以及数组都要在堆上分配,但是随着JIT编译器的发展与逃逸技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化发生,所有的对象都分配在堆上也不是变的那么“绝对”了。详解请学习我的:JVM之堆的体系结构
标签:需要 工作 加锁 私有 rtu jdb 栈内存 结构 情况下
原文地址:https://www.cnblogs.com/jalja365/p/12184872.html