jvm学习

jvm主要分为四个部分:
1、类加载器:在JVM启动时或者在类运行时将需要的class加载到JVM中(加载,检查,准备,解析,初始化),加载机制为双亲委派机制,目的是为了防止重复加载,当一个java程序需要使用某个类时,如果此类还未被加载到内存中,jvm会通过以上步骤对类进行初始化,类的加载是把类的.class读到内存中,通常是创建一个字节数组读入.class,然后产生与所加载的类对应的class对象,加载完成之后,进入连接阶段包括验证,准备(为静态变量分配内存并设置默认的初始化值)和解析(将符号引用替换为直接引用),最后进行初始化(a.如果父类没有初始化则初始化父类,所以JVM最先初始化的总是java.lang.Object类。;b、执行初始化语句)
类加载器一共有四种:
BootStrapClassLoader。它是最顶层的类加载器,是由C++编写而成, 已经内嵌到JVM中了。在JVM启动时会初始化该ClassLoader,它主要用来读取Java的核心类库JRE/lib/rt.jar中所有的class文件,这个jar文件中包含了java规范定义的所有接口及实现。
ExtensionClassLoader。它是用来读取Java的一些扩展类库,如读取JRE/lib/ext/*.jar中的包等(这里要注意,有些版本的是没有ext这个目录的)。
AppClassLoader。它是用来读取CLASSPATH下指定的所有jar包或目录的类文件,一般情况下这个就是程序中默认的类加载器。
CustomClassLoader。它是用户自定义编写的,它用来读取指定类文件 。基于自定义的ClassLoader可用于加载非Classpath中(如从网络上下载的jar或二进制)的jar及目录、还可以在加载前对class文件优一些动作,如解密、编码等。

当一个类加载器接受到加载类的请求时,首先委托给父类加载器,依次递归,如果父类加载器可以完成类的加载,则成功返回,如果父加载器无法完成加载任务,将抛出ClassNotFoundException异常后,再调用自己的findClass()方法进行加载,依次类推。

2、内存区域:
包括方法区:类似于存储类结构信息的地方,包括常量池,静态变量,构造函数等,运行时常量池;
堆:存储java实例和对象,gc回收的区域。方法区和堆是线程共享,异常是oom,对象不一定
栈:私有,每创建一个线程时,jvm就会为这个线程创建一个对应的Java栈,在这个java栈中会存在多个栈桢,每运行一个方法就创建一个栈帧,用于存储局部变量表、操作栈、方法返回值等。每一个方法从调用直至执行完成的过程,就对应一个栈帧在java栈中入栈到出栈的过程。所以java栈是现成私有的。异常:stackoverflowerror
程序计数器:用于保存当前线程执行的内存地址。由于JVM程序是多线程执行的(线程轮流切换),所以为了保证线程切换回来后,还能恢复到原先状态,就需要一个独立的计数器,记录之前中断的地方
本地方法栈:和java栈的作用差不多,只不过是为JVM使用到的native方法服务的。线程私有。

3、执行引擎:负责执行class文件中包含的字节码指令(执行引擎的工作机制,这里也不细说了,这里主要介绍JVM结构);
4、本地方法接口:主要是调用C或C++实现的本地方法及返回结果。

jvm垃圾检测回收算法:
检测:
引用计数法(无法解决循环引用的场景,引用计数器要求在每次因引用产生和消除的时候,需要伴随一个加 减法操作,对系统性能会有一定的影响);
可达性分析算法
回收:
标记清除法:效率低,会产生大量碎片,对于大对象的内存分配,不连续的内存 空间分配效率低于连续空间。 是现代垃圾回收算法的思想基础。
复制算法:为了解决标记清除算法效率低的问题。 该算法效率高,并且没有内存碎片,但是只能使用一半 的系统内存。适用于新生代。
标记压缩法:为了解决复制算法只能使用1/2内存的问题。 适用于垃圾对象多的情况,适用于老年代。
分代算法:将内存区间根据对象的生命周期分为两块,每块特点不 同,使用回收算法也不同,从而提升回收效率。
将对象按其生命周期的不同划分成:年轻代(Young Generation)、年老代(Old Generation)、持久代(Permanent Generation)。其中持久代主要存放的是类信息,所以与java对象的回收关系不大,与回收息息相关的是年轻代和年老代。年轻代被分为3个部分–Enden区和两个Survivor区(From和to)当Eden区被对象填满时,就会执行Minor GC。并把所有存活下来的对象转移到其中一个survivor区(假设为from区)。Minor GC同样会检查存活下来的对象,并把它们转移到另一个survivor区(假设为to区)。这样在一段时间内,总会有一个空的survivor区。经过多次GC周期后,仍然存活下来的对象会被转移到年老代内存空间。通常这是在年轻代有资格提升到年老代前通过设定年龄阈值来完成的。需要注意,Survivor的两个区是对称的,没先后关系,from和to是相对的。
年老代:在年轻代中经历了N次回收后仍然没有被清除的对象,就会被放到年老代中,可以说他们都是久经沙场而不亡的一代,都是生命周期较长的对象。对于年老代和永久代,就不能再采用像年轻代中那样搬移腾挪的回收算法,因为那些对于这些回收战场上的老兵来说是小儿科。通常会在老年代内存被占满时将会触发Full GC,回收整个堆内存。
持久代:用于存放静态文件,比如java类、方法等。持久代对垃圾回收没有显著的影响。

默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 ),即:新生代 ( Young ) = 1/3 的堆空间大小。老年代 ( Old ) = 2/3 的堆空间大小。其中,新生代 ( Young ) 被细分为 Eden 和 两个 Survivor 区域,这两个 Survivor 区域分别被命名为 from 和 to,以示区分。
默认的,Edem : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定 ),即: Eden = 8/10 的新生代空间大小,from = to = 1/10 的新生代空间大小。
JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor 区域是空闲着的。
在这里插入图片描述

分区算法:将这个堆空间划分成连续不同的小区间,每个区间独立 使用、独立回收。好处是:可以控制一次回收多少的小 空间,避免GC时间过长,造成系统停顿。

当new一个对象时,判断类是否已经被加载过(加载,检查,准备,解析,初始化),如果没有被加载过则去加载,否则为对象分配内存空间(对象不一定在堆上,当这个对象被别的线程引用时,对象就会放在堆上,如果没有被别的线程引用,则没有逃逸,优先在栈上分配,再在年轻代上分配对象,如果内存不够,则进行垃圾回收,再不行就会在老年代分配空间
如果堆上的地址是规整的话直接分配,采用指针碰撞,如果不是规整的话则采用空闲列表来分配空间,并发问题的解决cas),内存空间初始化,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值