JVM
1,虚拟机得发展
1)HostSpot VM(sun)
以前使用范围最广的java虚拟机
2) JRockit VM(BEA)
号称“世界上最快的Java虚拟机”
3) Dalvik VM(Google)及区块链/GoLang
4) HostSpot VM(ORACLE)
目前世界用的最广的java虚拟机
模块化----->混合语言------>多核并行------>丰富语言------>64位------>更强垃圾回收
java11的垃圾回收ZGC,回特别快,基本是在10ms之内
openJDK与Oracle开发的99%一样 ,但是openJDK是免费的
2,JVM的整体
内存是jvm的五脏六腑
1)内存分配
2) 垃圾回收
3.运行时数据区
JVM在运行过程中会把它所管理的内存划分成若干不同的数据区域
私有线程:程序计数器,虚拟机栈,本地方法栈
共享线程:堆,方法区
4.程序计数器(唯一不会OOM)
指向当前线程正在执行的字节码指令的地址(行号)
为什么需要程序计数器?
1,java是多线程的,意味着线程切换确保多线程情况下的程序正常执行
5.栈:数据结构
入口和出口只有一个
特点:先进后出
为什么要JVM使用栈
6.虚拟机栈
虚拟机栈(大小设置 -Xss 1M)
储存当前线程运行方法所需要的数据,指令返回地址
什么时候需要调整虚拟机栈的大小?
要创建大量线程的时候,值要变小,因为内存就那么大,调小才能变多
栈帧
每个方法在执行的同时都会创建一个栈帧。
栈帧主要包括:
1.局部变量表
2.操作数栈
3.动态连接
4.返回地址
方法会打包栈帧,放到虚拟机的栈中,每个方法都会创建栈帧,栈 顶一顶是虚拟机正在执行
7.本地方法 栈
本地方法栈保存的是native方法的信息,当一个JVM创建的线程调用native方法后JVM不再为其在
虚拟机栈中创建栈帧,JVM只是简单的动态链接并直接调用native方法
虚拟机规范无强制规定,各版本虚拟机自由实现HostSpot直接把本地方法栈和虚拟机栈合二为一
8.线程共享的区域
方法区(永久代(JDK1.7和以前),元空间(JDK1.8))
1),类信息
2),常量
3),静态变量
4).变异后的代码
Java堆(-Xms;-Xmx;-Xmn)
-Xms:最小 -Xmx:最大 -Xmn:新生代大小
-Xm256M 大小是根据内存计算的 32位 1GB 64位 32GB
堆是需要重点关注的一块区域,因为涉及到内存的分配(new关键字,反射等)与回收(回收算法,收集 器等)几乎所有的对象都在堆中分配
9,JVM各版本内存区域的变化
运行时常量池
Class文件中的常量池(编译器生成的各种字面量和符号引用)会在类加载后被放入这个区域
符号引用:
字面量:String a="aaa"
JDK1.6
运行时常量池在方法去中
JDK1.7
运行时常量池在堆中
JDK1.8
去永久代,使用元空间(空间带线啊哦只受制于机器的内存)替代永久代
永久代参数 -XX:PermSize;-XX:MaxPermSize =100M 超过100M OOM()
元空间参数 -XX:MetaspaceSize; -XX:MaxMetaspaceSize
why?
永久代来存储类信息、常量、静态变量等数据不是个好主意, 很容易遇到内存溢出的问题。 对永久代进行调优是很困难的,同时将元空间与堆的垃圾回收进行了隔离,避免永久代引发的Full GC和OOM等问题;
在反射和动态代理,会大量产生永久带
元空间,是根据电脑内存相关
10.直接内存
不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域;
1.如果使用了NIO,这块区域会被频繁使用,在java堆内可以用directByteBuffer对象直接引用并操作;
2.这块内存不受java堆大小限制,但受本机总内存的限制,可以通过MaxDirectMemorySize来设置(默认与堆内存最大值一样),所以也会出现OOM异常;
3.避免了在Java 堆和Native 堆中来回复制数据,能够提高效率
什么时候要有 直接内存?
可以增加读取速度
例如kafka,为什么小设置小一点,留一点给本地内存
设置直接内存,默认和堆大小一样
功能
1. 以栈帧的方式存储方法调用的过程,并存储方法调用过程中基本数据类型的变量(int、short、long、byte、float、double、boolean、char等)以及对象的引用变量,其内存分配在栈上,变量出了作用域就会自动释放;(stackoverflow,OOM)
2.而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中;
线程独享还是共享
1.栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。 堆内存中的对象对所有线程可见。
2.堆内存中的对象可以被所有线程访问。
空间大小
1.栈的内存要远远小于堆内存,栈的深度是有限制的,可能发生StackOverFlowError问题。