1、本地方法栈和程序计数器 ==》偏底层一般不会接触到
2、方法区 ==》对应为永久代
3、虚拟机栈(stack) ==》对应为栈
4、堆(heap) ==》对应里面有新生代+老年代
stack(栈内存 ) heap(堆内存) 永久代
5、栈内存
1)线程私有
2)生命周期和线程相同
3)主要存放内容
4)基本数据类型(int,char,float,double…)
5)对象的引用,指向了对象在堆内存中起始地址 ==》Object object = new Object(); ==》object就是对象的引用
6)通过-Xss参数配置 ==》假设只给栈内存分配了100MB、一个线程假设只分配1MB那么最多只能启动100个线程、栈内存一般比堆内存要小的多 ==》一般分配为1024KB
6、堆内存示意图
堆内存示意图的解释:【超级重点】
1)首先一个对象被创建的时候先进入到新生代里面新生代首先会进入到Eden区域(伊甸园)里面,Eden里面存了很多的对象,那么创建object对象的时候可能会创建成千上万次、那么随着创建的次数越多Eden区会满、那么满了怎么办呢?
2)这个时候新生代会做一次扫描,扫描Eden区和S1,把里面有用的对象进行标记,然后把Eden和S1里面有用的对象全部复制放进S0里面,那么没用的对象就会被全部清空,S0接着运行,过一段时间Eden又满了,那么新生代再次扫描Eden和S0,对有用的对象进行复制然后放进S1区域里面,然后把Eden和S0进行清空,如此循环S0和S1轮流会有一个保持为空,survivor区就叫做存活区域有点像仓库的概念。
3)要是在扫描的时候发现有用的对象很多,要是空的S0或者S1装不下怎么办? ==》这个时候放不下就会进行升级往老年代内存里面进行存放,老年代的内存一般都是比较大的
4)那假如老年代满了怎么办呢?就会进行对新生代和老年代的全扫描进行全局的垃圾回收,扫描之后保留有用的对象,大部分没用的对象其实在新生代就被垃圾回收了,根本上就进入不到老年代里面,真正能进入到S0或者S1区域的对象其实很少,因为一个对象的存活周期非常的短,Eden:S0:S1的空间比例为8:1:1
5)那么什么时候会进入到老年代内存里面呢?有3种情况可能【重点】
1)当新生代内存不够的时候
2)当某个对象在新生代发生GC垃圾回收达到15次之后,任然还是有效的,每存活一次年龄加1,年龄为15的时候那么就可以存放到老年代内存里面了
3)如果一个对象刚创建的时候特别大,比如大于5MB,因为新生代本身才1MB,这种就直接进入到老年代
堆内存 = 年轻代+老年代
年轻代 = Eden+Survivor
Survivor = From Space(s0)+To Space(s1)
7、堆内存
1)堆内存是Jvm中空间最大的区域 ==》如果总的内存为2GB那么堆内存至少为1024MB要占上1/2
2)所有线程共享堆
3)所有的数组以及内存对象的实例都在此区域分配
4)堆内存大小通过参数进行配置
-Xmx:最大堆内存
-Xms:最小堆内存
5)堆内存构成
– 新生代:包括三块区域,eden、from survivor(s0)、to survivor(s1)
– 老年代:old gen
Object o = new Object()
其中,o存放在栈内存中,new Object()存放在堆内存中,变量o是Object对象的引用,o上存放了Object对象占用内存的起始地址
8、永久代
永久代也叫(Method Area)
各线程共享,主方法区要存放类信息、常量、静态变量
如:public static int a = 10
垃圾回收行为比较少见
年轻代 = Eden+Survivor
Survivor = From Space(s0) + To Space(s1)
年轻代 = Eden+From Space+To Space
堆内存 = 年轻代+老年代
堆内存=Eden+From Space+To Space+老年代
9、Java8的新变化
Java8从Jvm中移除了PermGen,使用Metaspace(元空间)来代替永久代
Metaspace不存在Jvm中,而是存在本地内存中配置元空间初始值和最大值参数:
-XX:MetaspaceSize=64m
-XX:MaxMetaspaceSize=64m
10、YoungGC和FullGC的概念(GC指的是垃圾回收 Garbage Collection)
新生代引发的GC叫YoungGC
老年代引发的GC叫FullGC
FullGC会引起整个Jvm的用户线程暂停,待垃圾回收完毕后,才继续运行
11、永久代的垃圾回收
永久代回收"性价比"比较低
主要回收
1)废弃的常量
2)无用的类
3)类的所有实例都已经被回收
4)加载该类的ClassLoader已经被回收
5)该类的Class对象没有在任何地方被引用
12、堆垃圾回收算法
1)标记-清除算法 ==》分为“标记”和“清除”两个阶段,标记完成后,统一回收,缺点是:效率,标记和清除过程效率都不高,空间,标记清除后会产生大量不连续的内存碎片
2)复制算法 ==》内存分为相等的两块,当一块内存用完,将存活对象复制到另外一块中,原内存一次性清理掉,复制时按照顺序分配内存,无内存碎片问题,新生代使用此算法 缺点是:将内存分为两半,利用率低
3)标记-压缩算法 ==》先对存活对象进行标记,让所有存活对象向一边移动,清理掉存活对象边界外的所有内存,老年代使用此算法
4)分代收集算法 ==》当代的商业虚拟机都采用“分代收集”,根据对象的存活周期的不同将内存划分成几块,一般Java堆分为新生代和老年代,新生代采用复制算法,老年代采用标记-压缩算法
垃圾收集器是内存回收算法的具体实现
没有完美的收集器
Jvm不同的区域可以采用不同的垃圾收集器组合,主要有:
–Serial收集器(串行)
–ParNew收集器(并行)
–CMS收集器(并发)
–G1(时间优先) ==》G1全称是Garbage First Garbage Collector,在jdk1.7u4中开始支持。Java9中默认的垃圾收集器,G1的设计原则就是简化性能优化的复杂性
目前CMS收集器和G1收集器用的是最多的==》性能测试jvm垃圾收集器G1和 CMS 的区别【杭州多测师】【杭州多测师_王sir】
13、内存溢出
1)堆内存溢出
堆内存中存在大量对象,这些对象都有被引用,当所有对象占用空间达到堆内存的最大值, 就会出现内存溢出OutOfMemory:Java heap space
2)永久代溢出
类的一些信息,如类名、访问修饰符、字段描述、方法描述等,所占空间大于永久代最大值,就会出现OutOfMemoryError:PermGen space
14、内存溢出的检测方法
Jdk/bin目录下有很多检测工具
图形界面:
–Jconsole
–Jvisualvm
命令行工具
–Jstat –gcutil pid 1000 100
–Jmap –histo pid | head -20
–Jmap –heap pid FullGC频率:建议单次FullGC时间<200ms
垃圾回收和CPU使用率
内存泄露和TPS
15、jvm常用的参数
-Xms2048m,初始堆大小,建议<物理内存的1/4,默认值为物理内存的1/64
-Xmx2048m,最大堆大小,建议与-Xms保持一致,默认值为物理内存的1/4
-Xmn512m,新生代大小,建议不超过堆内存的1/2
-Xss256k,线程堆栈大小,建议256k
-XX:PermSize=256m,永久代初始值,默认值为物理内存的1/64
-XX:MaxPermSize=256m,永久代最大值,默认值为物理内存的1/4
-XX:SurvivorRatio=8:年轻带中Eden区和Survivor区的比例,默认为8:1,即Eden(8), From Space(1),ToSpace(1)
-XX:+UseConcMarkSweepGC:开启CMS垃圾回收器
16、JDK自带工具Jvisualvm监控Tomcat服务器
查看整个垃圾回收的过程和时间等等