JVM笔记

组成:

  1. 类加载子系统:负责从文件系统过网络加载claSS信息,加载的信息存储于方法区.

  2. 方法区:存放类信息,常量信息,常量池信息,包括字符串字面量和常量字符.

  3. 堆:在java虚拟机启动的时候建立堆,几乎所有的对象实例都存放于堆中,堆空间是所有线程空间共享的.

  4. 直接内存:NIO时使用,直接操作内存,比操作堆效率更高.

  5. 栈:每个虚拟机线程都有一个独立的栈,一个线程的java栈在线程创建的时候被创建,java栈中保存着局部变量,方法参数,方法调用,返回值

  6. 本地方法栈:与java栈类似,最大的不同是本地方法栈用于本地方法(c编写)调用

  7. 垃圾收集系统(GC)

  8. PC(program counter)寄存器:每个线程的私有空间,jvm会为每个线程创建pc寄存器,在任意时刻,一个java线程总是在执行一个方法,这个方法被称为当前方法,如果当前方法不是本地方法,pc寄存器就会执行当前正在被执行的指令,如果是本地方法,则pc寄存器的值为undefined,寄存器存放当前执行环境指针,程序计数器,操作栈指针,计算的变量指针等信息.

  9. 执行引擎:执行字节码

堆解决的是数据存储问题.

栈解决的是程序运行问题.

方法区是辅助栈的一块永久区,解决栈的信息产生,是先决条件.

堆:

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

新生代:

新生代存放新生长的对象或者年龄不大的对象

新生代由eden(伊甸园)区,S0(from)区,S1(to)区组成,其中S0与S1区大小相等可以角色互换的空间,eden区存放刚刚创建的对象

eden区的对象经过一个GC后,如果对象还存活则转移至S0区或S1区

新生代中每经历过一次GC,如果对象还存活,那么他的年龄就会增加1,默认情况下,当年龄达到15的时候,如果对象依然存活,该对象将有新生代转移到老年代

S0区与S1区设计原理基于复制算法,当对象经过第一次GC后被移动到S0或者S1,假设存于S0中,当S0快满的时候,GC将仍被使用的对象转移至S1中,然后将S0中的对象全部删除,当eden区再次转移对象时,则转移至S1中,这样循环往复.

老年代(tenured区)

老年代用于存放一直在使用的对象,老年代的GC不是很频繁,但是老年代中的对象不被引用,一样会被GC回收.

栈:

一块线程私有的内存空间,一般由三部分组成:局部变量表,操作数栈,帧数据区

局部变量表:用于局部变量及报错函数参数(Exception e)

操作数栈:主要保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间

帧数据区:除了局部变量表和操作数栈外,栈还需要一些数据来支持常量池的解析,这里帧数据区保存着访问常量池的指针,方便程序访问常量池...另外当函数返回或者出现异常的时候,虚拟机必须有一个异常处理表,方便发送异常时候找到的异常代码,异常处理表也是帧数据区的一部分

方法区:

一块所有线程共享的区域, 用于存放编译期生成的各种字面量和符号引号,这些内容将在类加载后进入方法区的运行时常量池中存放。

方法区中的String.intern问题

jdk1.6中 常量池在方法区中,方法区在Prem(永久代)区中 Prem区存在堆中,但是堆与方法区逻辑上是独立的

jdk1.7中 将常量池从方法区中移除,在堆中划分一块区域用作常量池

jdk1.8中,没有了Prem(永久代)区,常量池与方法区都放到了一个与堆不相连的区域,叫做元空间

JVM虚拟机参数:

 堆分配参数:

-XX:+PrintGC 使用这个参数,只要遇到GC,就会打印日志

-XX:+UseSerialGC 配置串行回收器

-XX:+PrintGCDetails 可以查看详细信息,包括各个区的情况

-Xms 设置初始堆大小

-Xmx 设置堆能获得的最大空间

-XX:PrintCommandLineFlags 可以将隐式或显式传给虚拟机的参数打印出来

-Xmn 设置新生代的大小,新生代的大小会影响老年代的大小,进而影响程序运行速度,新生代大小一般为堆的1/3或1/4

-XX:SurvivorRatio 用来设置新生代中eden区和S0/S1区的比例   含义:-XX:SurvivorRatio=eden/S0=eden/S1  即若新生代总大小为300M,设置-XX:SurvivorRatio=2,则表示eden大小/S0大小=2,则表示eden区150M, S0和S1各75M

尽可能地将对象预留在新生代,减少老年代GC(pull GC)次数

-XX:Ratio 设置新生代和老年代比例  -XX:Ratio=老年代/新生代

堆内存溢出处理:

-XX:HeapDumpOnOutOfMemoryError   在内存溢出时导出整个堆信息

-XX:HeapDumpPath 设置导出堆信息存放路径

新生代晋升老年代:

-XX:MaxTenuringThreshold   默认情况下是15  即经过15次YGC,仍没有被回收,则会进入老年代.

另外较大的对象,eden区无法存放的时候,也会直接进入老年代

-XX:PretenureSizeThreshold,控制超过指定大小后直接进入老年代

栈分配参数:

-Xss 指定线程最大栈空间-函数调用的最大深度

垃圾收集算法:

比较古老的方法:

引用计数法:当对象被引用的时候计数器加1,引用失效的时候计数器减1,存在问题,无法解决循环引用的问题,浪费内存空间

标记清除法:将引用失效的对象进行标记,然后由GC进行回收,这种算法会引起垃圾回收后内存空间不连续

新生代算法:

复制算法:核心思想是将内存区域分成两块,每次只使用其中的一块,在垃圾回收时,将正在使用内存块中留存的对象复制到未被使用的内存块中,之后清除之前正在使用的内存块中的所有对象,反复交换两个内存的角色,完成垃圾收集.

复制算法的应用:新生代中S0与S1之前就是使用这个算法(YGC).

老年代算法:

标记压缩法:标记压缩法在标记清除法之上进行优化,把存活的对象压缩到内存的一端,然后进行垃圾清理

标记压缩法的应用:老年代中使用标记压缩法(FULL GC)

为什么新生代与老年代算法不同?

新生代对象变化频繁,采用复制算法效率较高,老年代对象引用相对比较稳定,回收频率较低,回收耗时较长,尽量减少老年代的回收.

posted @ 2019-10-24 11:12  夏了夏天丶  阅读(123)  评论(0编辑  收藏  举报