赞
踩
概念:JVM把文件.class字节码加载到内存,对数据进行校验,转换和解析,并初始化,最终形成可以被虚拟机直接使用的java类型,这就是虚拟机的类加载机制
以下是JVM的概念图
类加载器的任务是根据一个类的全限定名来读取此类的二进制字节流到JVM中,然后转换为一个与目标类对应的java.lang.Class对象实例
在虚拟机提供了4种类加载器
⚪原理
原理:当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。
个人理解:
即每个儿子都不愿意干活,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己想办法去完成,这就是传说中的双亲委派模式
双亲委派机制的作用
个人解释:
试想,如果没有双亲委派模型而是由各个类加载器自行加载的话,如果用户编写了一个java.lang.Object的同名类并放在ClassPath中,多个类加载器都去加载这个类到内存中,系统中将会出现多个不同的Object类,那么类之间的比较结果及类的唯一性将无法保证,因为Object都各不相同那么程序运行启动就会出错,也保证了JVM能够正常的安全运行。
(1)JVM运行时会分配好方法区和堆,而JVM每遇到一个线程,就为其分配一个程序计数器、Java栈、本地方法栈,当线程终止时,三者(程序计数器、Java栈、本地方法栈)所占用的内存空间也会释放掉。
(2)程序计数器、Java栈、本地方法栈的生命周期与所属线程相同,而方法区和堆的生命周期与JAVA程序运行生命周期相同,所以gc只发生在线程共享的区域(大部分发生在Heap上)
♦有时候也称为永久代(Permanent Generation),在方法区中,存储了每个类的信息(包括类的名称、修饰符、方法信息、字段信息)、类中静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息以及编译器编译后的代码等
♦当开发人员在程序中通过Class对象中的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域,同时方法区域也是全局共享的,在一定的条件下它也会被GC,在这里进行的GC主要是方法区里的常量池和类型的卸载。当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。—OOM
♦在方法区中有一个非常重要的部分就是运行时常量池,用于存放静态编译产生的字面量和符号引用。运行时生成的常量也会存在这个常量池中,比如String的intern方法。它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。
为什么元空间又称为非堆: 因为在内存模型中他存储的数据和堆有些许不同,所以习惯性把他从堆中单独区分出来。 方法区属于非堆内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。它是在 Java 虚拟机启动时创建的。
JVM采用本地方法堆栈来支持native方法的执行,此区域用于存储每个native方法调用的状态。
本地方法栈与Java栈的作用和原理非常相似。**区别只不过是Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的。**在JVM规范中,并没有对本地方法栈的具体实现方法以及数据结构作强制规定,虚拟机可以自由实现它。在HotSopt虚拟机中直接就把本地方法栈和Java栈合二为一。
首先会在方法区加载Class模板,每个模板都有该类的属性以及方法和常量池,以及静态变量随着类加载而加载到静态方法区,并在java堆中生成一个代表这个类的Class对象的内存区域,为类变量分配内存并设置类变量初始值,例如String类型为null, 而后在栈中存储该对象的引用地址,地址指向堆中类的内存地址,最后初始化,例如构造方法,赋值给堆中的对象内存数据中。每一个线程都会给他分配指定的 java栈,程序计数器,本地方法栈,所以说这三个是线程独享,是线程安全,而堆和方法区大家一起使用的,因而是线程不安全
GC的基本原理:将内存中不再被使用的对象进行回收,GC中用于回收的方法称为收集器,由于GC需要消耗一些资源和时间,Java在对对象的生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽可能的缩短GC对应用造成的暂停。
个人理解:
JVM的内存结构包括五大区域:程序计数器、虚拟机栈、本地方法栈、堆区、方法区。
- ♦ 引用计数法------过时
概念: 引用计数是垃圾收集器中的早期策略。堆中每个对象实例都有一个引用计数。当一个对象被创建时,就将该对象实例分配给一个变量,该变量计数设置为1。当任何其它变量被赋值为这个对象的引用时,计数加1,引用计数器为0的对象实例可以被当作垃圾收集。当一个对象实例被垃圾收集时,它引用的任何对象实例的引用计数器减1。
缺点: 这样很浪费资源,要对所有对象引用计数,并且计数器本身也浪费资源
- ♦ 标记-清除(Mark-Sweep)算法
标记-清除算法分为两个阶段:标记阶段和清除阶段。标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。(需要两次扫描)
主要缺点:
1.一个是效率问题,标记和清除过程的效率都不高。
2.另一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致:当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前出发另一次垃圾收集动作。
- ♦ *标记-整理(Mark-Compact)算法====标记-清除-整理
为了解决Copying算法的缺陷,充分利用内存空间,提出了Mark-Compact算法。该算法标记阶段和Mark-Sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。(需要三次扫描)
优点:减少了内存碎片
缺点:更加降低了效率
- ♦ 复制算法
♦分代收集(Generational Collection)算法------堆分区使用不同算法(重点)
⚪概念:
分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和年轻代,在堆区之外还有一个代就是永久代,它用来存储class类、常量、方法描述等。对永久代的回收主要回收两部分内容:废弃常量和无用的类。
⚪使用:
■年轻代中jvm使用的是:Mark-copy(标记-复制)算法
■永久代(Permanent Generation)的回收算法:
永久代(permanent generation) 也称为“方法区(method area)”,他存储class对象和字符串常量。所以这块内存区域绝对不是永久的存放从老年代存活下来的对象的。在这块内存中有可能发生垃圾回收。发生在这里垃圾回收也被称为major GC。
Minor GC触发条件
Full GC触发条件
♦OOM - Out of Memory,内存溢出
软件所需要的内存远远超出了你主机内安装的内存所承受大小,就叫内存溢出。此时软件或游戏就运行不了,系统会提示内存溢出,有时候会自动关闭软件,重启电脑或者软件后释放掉一部分内存又可以正常运行该软件
-XX 参数被称为不稳定参数,之所以这么叫是因为此类参数的设置很容易引起JVM 性能上的差异,使JVM 存在极大的不稳定性。如果此类参数设置合理将大大提高JVM 的性能及稳定性。
不稳定参数语法规则:
1.布尔类型参数值
-XX:+<option> '+'表示启用该选项
-XX:-<option> '-'表示关闭该选项
2.数字类型参数值:
-XX:<option>=<number> 给选项设置一个数字类型值,可跟随单位,例如:'m'或'M'表示兆字节;'k'或'K'千字节;'g'或'G'千兆字节。32K与32768是相同大小的。
3.字符串类型参数值:
-XX:<option>=<string> 给选项设置一个字符串类型值,通常用于指定一个文件、路径或一系列命令列表。
例如:-XX:HeapDumpPath=./dump.core
♦JVM参数示例
配置: -Xmx4g –Xms4g –Xmn1200m –Xss512k -XX:NewRatio=4 -XX:SurvivorRatio=8 -XX:PermSize=100m
-XX:MaxPermSize=256m -XX:MaxTenuringThreshold=15
解析:
-Xmx4g:堆内存最大值为4GB。
-Xms4g:初始化堆内存大小为4GB 。
-Xmn1200m:设置年轻代大小为1200MB。增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-Xss512k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1MB,以前每个线程堆栈大小为256K。应根据应用线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=8:设置年轻代中Eden区与Survivor区的大小比值。设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
-XX:PermSize=100m:初始化永久代大小为100MB。
-XX:MaxPermSize=256m:设置持久代大小为256MB。
-XX:MaxTenuringThreshold=15:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。
以上是我对JVM的个人理解以及引用了一些大佬的概念,希望大家一起学习探讨~有错误的地方希望能给我指出 0.0
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。